@ckeditor/ckeditor5-engine 47.6.1 → 48.0.0-alpha.1

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 (258) hide show
  1. package/LICENSE.md +1 -1
  2. package/{src → dist}/engineconfig.d.ts +6 -15
  3. package/dist/index-editor.css +38 -15
  4. package/dist/index.css +37 -37
  5. package/dist/index.css.map +1 -1
  6. package/{src → dist}/index.d.ts +0 -1
  7. package/dist/index.js +588 -94
  8. package/dist/index.js.map +1 -1
  9. package/{src → dist}/model/model.d.ts +10 -4
  10. package/{src → dist}/model/selection.d.ts +1 -1
  11. package/{src → dist}/view/downcastwriter.d.ts +3 -2
  12. package/{src → dist}/view/element.d.ts +2 -2
  13. package/{src → dist}/view/matcher.d.ts +4 -2
  14. package/dist/view/styles/background.d.ts +18 -0
  15. package/{src → dist}/view/styles/border.d.ts +0 -12
  16. package/{src → dist}/view/styles/margin.d.ts +0 -13
  17. package/{src → dist}/view/styles/padding.d.ts +0 -13
  18. package/{src → dist}/view/styles/utils.d.ts +12 -0
  19. package/package.json +20 -39
  20. package/src/controller/datacontroller.js +0 -522
  21. package/src/controller/editingcontroller.js +0 -181
  22. package/src/conversion/conversion.js +0 -606
  23. package/src/conversion/conversionhelpers.js +0 -33
  24. package/src/conversion/downcastdispatcher.js +0 -563
  25. package/src/conversion/downcasthelpers.js +0 -2160
  26. package/src/conversion/mapper.js +0 -1050
  27. package/src/conversion/modelconsumable.js +0 -331
  28. package/src/conversion/upcastdispatcher.js +0 -470
  29. package/src/conversion/upcasthelpers.js +0 -952
  30. package/src/conversion/viewconsumable.js +0 -541
  31. package/src/dataprocessor/basichtmlwriter.js +0 -22
  32. package/src/dataprocessor/dataprocessor.js +0 -5
  33. package/src/dataprocessor/htmldataprocessor.js +0 -107
  34. package/src/dataprocessor/htmlwriter.js +0 -5
  35. package/src/dataprocessor/xmldataprocessor.js +0 -127
  36. package/src/dev-utils/model.js +0 -396
  37. package/src/dev-utils/operationreplayer.js +0 -116
  38. package/src/dev-utils/utils.js +0 -122
  39. package/src/dev-utils/view.js +0 -990
  40. package/src/engineconfig.js +0 -5
  41. package/src/index.js +0 -134
  42. package/src/legacyerrors.js +0 -17
  43. package/src/model/batch.js +0 -98
  44. package/src/model/differ.js +0 -1288
  45. package/src/model/document.js +0 -398
  46. package/src/model/documentfragment.js +0 -332
  47. package/src/model/documentselection.js +0 -1026
  48. package/src/model/element.js +0 -323
  49. package/src/model/history.js +0 -206
  50. package/src/model/item.js +0 -5
  51. package/src/model/liveposition.js +0 -93
  52. package/src/model/liverange.js +0 -121
  53. package/src/model/markercollection.js +0 -436
  54. package/src/model/model.js +0 -866
  55. package/src/model/node.js +0 -371
  56. package/src/model/nodelist.js +0 -244
  57. package/src/model/operation/attributeoperation.js +0 -172
  58. package/src/model/operation/detachoperation.js +0 -87
  59. package/src/model/operation/insertoperation.js +0 -153
  60. package/src/model/operation/markeroperation.js +0 -136
  61. package/src/model/operation/mergeoperation.js +0 -184
  62. package/src/model/operation/moveoperation.js +0 -179
  63. package/src/model/operation/nooperation.js +0 -48
  64. package/src/model/operation/operation.js +0 -78
  65. package/src/model/operation/operationfactory.js +0 -44
  66. package/src/model/operation/renameoperation.js +0 -128
  67. package/src/model/operation/rootattributeoperation.js +0 -173
  68. package/src/model/operation/rootoperation.js +0 -106
  69. package/src/model/operation/splitoperation.js +0 -214
  70. package/src/model/operation/transform.js +0 -2211
  71. package/src/model/operation/utils.js +0 -217
  72. package/src/model/position.js +0 -1041
  73. package/src/model/range.js +0 -880
  74. package/src/model/rootelement.js +0 -82
  75. package/src/model/schema.js +0 -1542
  76. package/src/model/selection.js +0 -814
  77. package/src/model/text.js +0 -92
  78. package/src/model/textproxy.js +0 -202
  79. package/src/model/treewalker.js +0 -313
  80. package/src/model/typecheckable.js +0 -16
  81. package/src/model/utils/autoparagraphing.js +0 -63
  82. package/src/model/utils/deletecontent.js +0 -509
  83. package/src/model/utils/getselectedcontent.js +0 -126
  84. package/src/model/utils/insertcontent.js +0 -750
  85. package/src/model/utils/insertobject.js +0 -135
  86. package/src/model/utils/modifyselection.js +0 -187
  87. package/src/model/utils/selection-post-fixer.js +0 -264
  88. package/src/model/writer.js +0 -1318
  89. package/src/view/attributeelement.js +0 -220
  90. package/src/view/containerelement.js +0 -91
  91. package/src/view/datatransfer.js +0 -106
  92. package/src/view/document.js +0 -139
  93. package/src/view/documentfragment.js +0 -251
  94. package/src/view/documentselection.js +0 -270
  95. package/src/view/domconverter.js +0 -1661
  96. package/src/view/downcastwriter.js +0 -1589
  97. package/src/view/editableelement.js +0 -74
  98. package/src/view/element.js +0 -1053
  99. package/src/view/elementdefinition.js +0 -5
  100. package/src/view/emptyelement.js +0 -83
  101. package/src/view/filler.js +0 -161
  102. package/src/view/item.js +0 -5
  103. package/src/view/matcher.js +0 -437
  104. package/src/view/node.js +0 -238
  105. package/src/view/observer/arrowkeysobserver.js +0 -40
  106. package/src/view/observer/bubblingemittermixin.js +0 -215
  107. package/src/view/observer/bubblingeventinfo.js +0 -49
  108. package/src/view/observer/clickobserver.js +0 -26
  109. package/src/view/observer/compositionobserver.js +0 -64
  110. package/src/view/observer/domeventdata.js +0 -63
  111. package/src/view/observer/domeventobserver.js +0 -81
  112. package/src/view/observer/fakeselectionobserver.js +0 -95
  113. package/src/view/observer/focusobserver.js +0 -166
  114. package/src/view/observer/inputobserver.js +0 -236
  115. package/src/view/observer/keyobserver.js +0 -36
  116. package/src/view/observer/mouseobserver.js +0 -26
  117. package/src/view/observer/mutationobserver.js +0 -219
  118. package/src/view/observer/observer.js +0 -92
  119. package/src/view/observer/pointerobserver.js +0 -26
  120. package/src/view/observer/selectionobserver.js +0 -318
  121. package/src/view/observer/tabobserver.js +0 -42
  122. package/src/view/observer/touchobserver.js +0 -26
  123. package/src/view/placeholder.js +0 -285
  124. package/src/view/position.js +0 -341
  125. package/src/view/range.js +0 -451
  126. package/src/view/rawelement.js +0 -115
  127. package/src/view/renderer.js +0 -1148
  128. package/src/view/rooteditableelement.js +0 -78
  129. package/src/view/selection.js +0 -594
  130. package/src/view/styles/background.d.ts +0 -33
  131. package/src/view/styles/background.js +0 -74
  132. package/src/view/styles/border.js +0 -316
  133. package/src/view/styles/margin.js +0 -34
  134. package/src/view/styles/padding.js +0 -34
  135. package/src/view/styles/utils.js +0 -219
  136. package/src/view/stylesmap.js +0 -941
  137. package/src/view/text.js +0 -110
  138. package/src/view/textproxy.js +0 -136
  139. package/src/view/tokenlist.js +0 -194
  140. package/src/view/treewalker.js +0 -389
  141. package/src/view/typecheckable.js +0 -19
  142. package/src/view/uielement.js +0 -194
  143. package/src/view/upcastwriter.js +0 -363
  144. package/src/view/view.js +0 -579
  145. package/theme/placeholder.css +0 -36
  146. package/theme/renderer.css +0 -9
  147. /package/{src → dist}/controller/datacontroller.d.ts +0 -0
  148. /package/{src → dist}/controller/editingcontroller.d.ts +0 -0
  149. /package/{src → dist}/conversion/conversion.d.ts +0 -0
  150. /package/{src → dist}/conversion/conversionhelpers.d.ts +0 -0
  151. /package/{src → dist}/conversion/downcastdispatcher.d.ts +0 -0
  152. /package/{src → dist}/conversion/downcasthelpers.d.ts +0 -0
  153. /package/{src → dist}/conversion/mapper.d.ts +0 -0
  154. /package/{src → dist}/conversion/modelconsumable.d.ts +0 -0
  155. /package/{src → dist}/conversion/upcastdispatcher.d.ts +0 -0
  156. /package/{src → dist}/conversion/upcasthelpers.d.ts +0 -0
  157. /package/{src → dist}/conversion/viewconsumable.d.ts +0 -0
  158. /package/{src → dist}/dataprocessor/basichtmlwriter.d.ts +0 -0
  159. /package/{src → dist}/dataprocessor/dataprocessor.d.ts +0 -0
  160. /package/{src → dist}/dataprocessor/htmldataprocessor.d.ts +0 -0
  161. /package/{src → dist}/dataprocessor/htmlwriter.d.ts +0 -0
  162. /package/{src → dist}/dataprocessor/xmldataprocessor.d.ts +0 -0
  163. /package/{src → dist}/dev-utils/model.d.ts +0 -0
  164. /package/{src → dist}/dev-utils/operationreplayer.d.ts +0 -0
  165. /package/{src → dist}/dev-utils/utils.d.ts +0 -0
  166. /package/{src → dist}/dev-utils/view.d.ts +0 -0
  167. /package/{src → dist}/legacyerrors.d.ts +0 -0
  168. /package/{src → dist}/model/batch.d.ts +0 -0
  169. /package/{src → dist}/model/differ.d.ts +0 -0
  170. /package/{src → dist}/model/document.d.ts +0 -0
  171. /package/{src → dist}/model/documentfragment.d.ts +0 -0
  172. /package/{src → dist}/model/documentselection.d.ts +0 -0
  173. /package/{src → dist}/model/element.d.ts +0 -0
  174. /package/{src → dist}/model/history.d.ts +0 -0
  175. /package/{src → dist}/model/item.d.ts +0 -0
  176. /package/{src → dist}/model/liveposition.d.ts +0 -0
  177. /package/{src → dist}/model/liverange.d.ts +0 -0
  178. /package/{src → dist}/model/markercollection.d.ts +0 -0
  179. /package/{src → dist}/model/node.d.ts +0 -0
  180. /package/{src → dist}/model/nodelist.d.ts +0 -0
  181. /package/{src → dist}/model/operation/attributeoperation.d.ts +0 -0
  182. /package/{src → dist}/model/operation/detachoperation.d.ts +0 -0
  183. /package/{src → dist}/model/operation/insertoperation.d.ts +0 -0
  184. /package/{src → dist}/model/operation/markeroperation.d.ts +0 -0
  185. /package/{src → dist}/model/operation/mergeoperation.d.ts +0 -0
  186. /package/{src → dist}/model/operation/moveoperation.d.ts +0 -0
  187. /package/{src → dist}/model/operation/nooperation.d.ts +0 -0
  188. /package/{src → dist}/model/operation/operation.d.ts +0 -0
  189. /package/{src → dist}/model/operation/operationfactory.d.ts +0 -0
  190. /package/{src → dist}/model/operation/renameoperation.d.ts +0 -0
  191. /package/{src → dist}/model/operation/rootattributeoperation.d.ts +0 -0
  192. /package/{src → dist}/model/operation/rootoperation.d.ts +0 -0
  193. /package/{src → dist}/model/operation/splitoperation.d.ts +0 -0
  194. /package/{src → dist}/model/operation/transform.d.ts +0 -0
  195. /package/{src → dist}/model/operation/utils.d.ts +0 -0
  196. /package/{src → dist}/model/position.d.ts +0 -0
  197. /package/{src → dist}/model/range.d.ts +0 -0
  198. /package/{src → dist}/model/rootelement.d.ts +0 -0
  199. /package/{src → dist}/model/schema.d.ts +0 -0
  200. /package/{src → dist}/model/text.d.ts +0 -0
  201. /package/{src → dist}/model/textproxy.d.ts +0 -0
  202. /package/{src → dist}/model/treewalker.d.ts +0 -0
  203. /package/{src → dist}/model/typecheckable.d.ts +0 -0
  204. /package/{src → dist}/model/utils/autoparagraphing.d.ts +0 -0
  205. /package/{src → dist}/model/utils/deletecontent.d.ts +0 -0
  206. /package/{src → dist}/model/utils/getselectedcontent.d.ts +0 -0
  207. /package/{src → dist}/model/utils/insertcontent.d.ts +0 -0
  208. /package/{src → dist}/model/utils/insertobject.d.ts +0 -0
  209. /package/{src → dist}/model/utils/modifyselection.d.ts +0 -0
  210. /package/{src → dist}/model/utils/selection-post-fixer.d.ts +0 -0
  211. /package/{src → dist}/model/writer.d.ts +0 -0
  212. /package/{src → dist}/view/attributeelement.d.ts +0 -0
  213. /package/{src → dist}/view/containerelement.d.ts +0 -0
  214. /package/{src → dist}/view/datatransfer.d.ts +0 -0
  215. /package/{src → dist}/view/document.d.ts +0 -0
  216. /package/{src → dist}/view/documentfragment.d.ts +0 -0
  217. /package/{src → dist}/view/documentselection.d.ts +0 -0
  218. /package/{src → dist}/view/domconverter.d.ts +0 -0
  219. /package/{src → dist}/view/editableelement.d.ts +0 -0
  220. /package/{src → dist}/view/elementdefinition.d.ts +0 -0
  221. /package/{src → dist}/view/emptyelement.d.ts +0 -0
  222. /package/{src → dist}/view/filler.d.ts +0 -0
  223. /package/{src → dist}/view/item.d.ts +0 -0
  224. /package/{src → dist}/view/node.d.ts +0 -0
  225. /package/{src → dist}/view/observer/arrowkeysobserver.d.ts +0 -0
  226. /package/{src → dist}/view/observer/bubblingemittermixin.d.ts +0 -0
  227. /package/{src → dist}/view/observer/bubblingeventinfo.d.ts +0 -0
  228. /package/{src → dist}/view/observer/clickobserver.d.ts +0 -0
  229. /package/{src → dist}/view/observer/compositionobserver.d.ts +0 -0
  230. /package/{src → dist}/view/observer/domeventdata.d.ts +0 -0
  231. /package/{src → dist}/view/observer/domeventobserver.d.ts +0 -0
  232. /package/{src → dist}/view/observer/fakeselectionobserver.d.ts +0 -0
  233. /package/{src → dist}/view/observer/focusobserver.d.ts +0 -0
  234. /package/{src → dist}/view/observer/inputobserver.d.ts +0 -0
  235. /package/{src → dist}/view/observer/keyobserver.d.ts +0 -0
  236. /package/{src → dist}/view/observer/mouseobserver.d.ts +0 -0
  237. /package/{src → dist}/view/observer/mutationobserver.d.ts +0 -0
  238. /package/{src → dist}/view/observer/observer.d.ts +0 -0
  239. /package/{src → dist}/view/observer/pointerobserver.d.ts +0 -0
  240. /package/{src → dist}/view/observer/selectionobserver.d.ts +0 -0
  241. /package/{src → dist}/view/observer/tabobserver.d.ts +0 -0
  242. /package/{src → dist}/view/observer/touchobserver.d.ts +0 -0
  243. /package/{src → dist}/view/placeholder.d.ts +0 -0
  244. /package/{src → dist}/view/position.d.ts +0 -0
  245. /package/{src → dist}/view/range.d.ts +0 -0
  246. /package/{src → dist}/view/rawelement.d.ts +0 -0
  247. /package/{src → dist}/view/renderer.d.ts +0 -0
  248. /package/{src → dist}/view/rooteditableelement.d.ts +0 -0
  249. /package/{src → dist}/view/selection.d.ts +0 -0
  250. /package/{src → dist}/view/stylesmap.d.ts +0 -0
  251. /package/{src → dist}/view/text.d.ts +0 -0
  252. /package/{src → dist}/view/textproxy.d.ts +0 -0
  253. /package/{src → dist}/view/tokenlist.d.ts +0 -0
  254. /package/{src → dist}/view/treewalker.d.ts +0 -0
  255. /package/{src → dist}/view/typecheckable.d.ts +0 -0
  256. /package/{src → dist}/view/uielement.d.ts +0 -0
  257. /package/{src → dist}/view/upcastwriter.d.ts +0 -0
  258. /package/{src → dist}/view/view.d.ts +0 -0
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
5
  import { logWarning, EmitterMixin, CKEditorError, compareArrays, toArray, toMap, isIterable, ObservableMixin, count, EventInfo, Collection, keyCodes, isText, env, remove as remove$1, insertAt, diff, fastDiff, isNode, isComment, indexOf, global, isValidAttributeName, first, getAncestors, DomEmitterMixin, getCode, isArrowKeyCode, scrollViewportToShowTarget, uid, spliceArray, priorities, isInsideSurrogatePair, isInsideCombinedSymbol, isInsideEmojiSequence } from '@ckeditor/ckeditor5-utils/dist/index.js';
6
- import { isObject, get, merge, set, isPlainObject, extend, debounce, isEqualWith, cloneDeep, isEqual, clone } from 'es-toolkit/compat';
6
+ import { isObject, get, merge, set, isPlainObject, extend, debounce, isEqualWith, cloneDeep, isEqual, clone, isEmpty } from 'es-toolkit/compat';
7
7
 
8
8
  // Each document stores information about its placeholder elements and check functions.
9
9
  const documentPlaceholders = new WeakMap();
@@ -267,8 +267,9 @@ let hasDisplayedPlaceholderDeprecationWarning = false;
267
267
  * The "text" option in the {@link module:engine/view/placeholder~enableViewPlaceholder `enableViewPlaceholder()`}
268
268
  * function is deprecated and will be removed soon.
269
269
  *
270
- * See the {@glink updating/guides/update-to-39#view-element-placeholder Migration to v39} guide for
271
- * more information on how to apply this change.
270
+ * See the `#view-element-placeholder` section in the `Update to v39.x` section in the
271
+ * {@glink updating/guides/updating-from-older-versions updating from older versions} guide
272
+ * for more information on how to apply this change.
272
273
  *
273
274
  * @error enableViewPlaceholder-deprecated-text-option
274
275
  */ logWarning('enableViewPlaceholder-deprecated-text-option');
@@ -1630,7 +1631,8 @@ ViewTextProxy.prototype.is = function(type) {
1630
1631
  * }
1631
1632
  * ```
1632
1633
  *
1633
- * Refer to the {@glink updating/guides/update-to-29##update-to-ckeditor-5-v2910 Migration to v29.1.0} guide
1634
+ * Refer to the `#update-to-ckeditor-5-v2910` section in the `Update to v29.x` section in the
1635
+ * {@glink updating/guides/updating-from-older-versions updating from older versions} guide
1634
1636
  * and {@link module:engine/view/matcher~MatcherPattern} documentation.
1635
1637
  *
1636
1638
  * @param pattern Pattern with missing properties.
@@ -1660,7 +1662,8 @@ ViewTextProxy.prototype.is = function(type) {
1660
1662
  * }
1661
1663
  * ```
1662
1664
  *
1663
- * Refer to the {@glink updating/guides/update-to-29##update-to-ckeditor-5-v2910 Migration to v29.1.0} guide
1665
+ * Refer to the `#update-to-ckeditor-5-v2910` paragraph in the Update to v29.x guide in the
1666
+ * {@glink updating/guides/updating-from-older-versions updating from older versions} guide
1664
1667
  * and the {@link module:engine/view/matcher~MatcherPattern} documentation.
1665
1668
  *
1666
1669
  * @param pattern Pattern with missing properties.
@@ -2534,7 +2537,9 @@ ViewTextProxy.prototype.is = function(type) {
2534
2537
  * Appends style definition to the styles object.
2535
2538
  */ function appendStyleValue(stylesObject, nameOrPath, valueOrObject) {
2536
2539
  let valueToSet = valueOrObject;
2537
- if (isObject(valueOrObject)) {
2540
+ // We don't want to merge it with existing value when it's array. It's because some styles can be defined
2541
+ // as array of layers (e.g. background-image) and in such case we want to override whole array instead of merging it with existing one.
2542
+ if (isObject(valueOrObject) && !Array.isArray(valueOrObject)) {
2538
2543
  valueToSet = merge({}, get(stylesObject, nameOrPath), valueOrObject);
2539
2544
  }
2540
2545
  set(stylesObject, nameOrPath, valueToSet);
@@ -17851,7 +17856,7 @@ ModelNode.prototype.is = function(type) {
17851
17856
  * selection.setTo( paragraph, 'on' );
17852
17857
  * ```
17853
17858
  *
17854
- * `Selection#setTo()`' method allow passing additional options (`backward`) as the last argument.
17859
+ * `Selection#setTo()` method allows passing additional options (`backward`) as the last argument.
17855
17860
  *
17856
17861
  * ```ts
17857
17862
  * // Sets backward selection.
@@ -35537,7 +35542,7 @@ function removeRangeContent(range, writer) {
35537
35542
  this._mergeOnRight();
35538
35543
  // TMP this will become a post-fixer.
35539
35544
  this.schema.removeDisallowedAttributes(this._filterAttributesAndChildrenOf, this.writer);
35540
- if (this.model._config?.get('experimentalFlags.modelInsertContentDeepSchemaVerification')) {
35545
+ if (this.model._config?.get('experimentalFlags.modelInsertContentDeepSchemaVerification') !== false) {
35541
35546
  this._removeDisallowedChildren(this._filterAttributesAndChildrenOf);
35542
35547
  }
35543
35548
  this._filterAttributesAndChildrenOf = [];
@@ -36863,8 +36868,7 @@ function getSearchRange(start, isForward) {
36863
36868
  return getSelectedContent(this, selection);
36864
36869
  }
36865
36870
  /**
36866
- * Checks whether the given {@link module:engine/model/range~ModelRange range} or
36867
- * {@link module:engine/model/element~ModelElement element} has any meaningful content.
36871
+ * Checks whether given `subject` has any meaningful content.
36868
36872
  *
36869
36873
  * Meaningful content is:
36870
36874
  *
@@ -36878,11 +36882,35 @@ function getSearchRange(start, isForward) {
36878
36882
  * However, a range containing an `<imageBlock></imageBlock>` (which would normally be marked in the schema as an object element)
36879
36883
  * is considered non-empty.
36880
36884
  *
36881
- * @param rangeOrElement Range or element to check.
36885
+ * @param subject Subject to check if includes meaningful content. Could be a model range, an element, a document fragment, or a
36886
+ * selection.
36882
36887
  * @param options.ignoreWhitespaces Whether text node with whitespaces only should be considered empty.
36883
36888
  * @param options.ignoreMarkers Whether markers should be ignored.
36884
- */ hasContent(rangeOrElement, options = {}) {
36885
- const range = rangeOrElement instanceof ModelRange ? rangeOrElement : ModelRange._createIn(rangeOrElement);
36889
+ */ hasContent(subject, options = {}) {
36890
+ let ranges;
36891
+ if (subject.is('selection')) {
36892
+ ranges = Array.from(subject.getRanges());
36893
+ } else if (subject.is('range')) {
36894
+ ranges = [
36895
+ subject
36896
+ ];
36897
+ } else {
36898
+ ranges = [
36899
+ ModelRange._createIn(subject)
36900
+ ];
36901
+ }
36902
+ for (const range of ranges){
36903
+ if (this._rangeHasContent(range, options)) {
36904
+ return true;
36905
+ }
36906
+ }
36907
+ return false;
36908
+ }
36909
+ /**
36910
+ * Checks whether given range has any meaningful content.
36911
+ *
36912
+ * Helper method for {@link #hasContent}.
36913
+ */ _rangeHasContent(range, options) {
36886
36914
  if (range.isCollapsed) {
36887
36915
  return false;
36888
36916
  }
@@ -37762,6 +37790,16 @@ const PERCENTAGE_VALUE_REGEXP = /^[+-]?[0-9]*([.][0-9]+)?%$/;
37762
37790
  */ function isPercentageStyleValue(string) {
37763
37791
  return PERCENTAGE_VALUE_REGEXP.test(string);
37764
37792
  }
37793
+ const sizeValues = [
37794
+ 'auto',
37795
+ 'cover',
37796
+ 'contain'
37797
+ ];
37798
+ /**
37799
+ * Checks if a string is a valid CSS `background-size` value token.
37800
+ */ function isSizeStyleValue(value) {
37801
+ return sizeValues.includes(value) || isLengthStyleValue(value) || isPercentageStyleValue(value);
37802
+ }
37765
37803
  const repeatValues = [
37766
37804
  'repeat-x',
37767
37805
  'repeat-y',
@@ -37797,6 +37835,27 @@ const attachmentValues = [
37797
37835
  */ function isAttachmentStyleValue(string) {
37798
37836
  return attachmentValues.includes(string);
37799
37837
  }
37838
+ const originValues = [
37839
+ 'border-box',
37840
+ 'padding-box',
37841
+ 'content-box'
37842
+ ];
37843
+ /**
37844
+ * Checks if string contains [background origin](https://developer.mozilla.org/en-US/docs/Web/CSS/background-origin) CSS value.
37845
+ */ function isOriginStyleValue(string) {
37846
+ return originValues.includes(string);
37847
+ }
37848
+ const clipValues = [
37849
+ 'border-box',
37850
+ 'padding-box',
37851
+ 'content-box',
37852
+ 'text'
37853
+ ];
37854
+ /**
37855
+ * Checks if string contains [background clip](https://developer.mozilla.org/en-US/docs/Web/CSS/background-clip) CSS value.
37856
+ */ function isClipStyleValue(string) {
37857
+ return clipValues.includes(string);
37858
+ }
37800
37859
  const urlRegExp = /^url\(/;
37801
37860
  /**
37802
37861
  * Checks if string contains [URL](https://developer.mozilla.org/en-US/docs/Web/CSS/url) CSS value.
@@ -37924,77 +37983,530 @@ const urlRegExp = /^url\(/;
37924
37983
  }
37925
37984
 
37926
37985
  /**
37927
- * Adds a background CSS styles processing rules.
37986
+ * CSS initial values for background longhand properties.
37987
+ */ const BACKGROUND_INITIAL_ARRAY_VALUES = {
37988
+ image: 'none',
37989
+ repeat: 'repeat',
37990
+ position: '0% 0%',
37991
+ size: 'auto',
37992
+ origin: 'padding-box',
37993
+ clip: 'border-box',
37994
+ attachment: 'scroll'
37995
+ };
37996
+ /**
37997
+ * CSS function names that represent image values in the `background` shorthand.
37998
+ */ const IMAGE_FUNCTIONS = [
37999
+ 'linear-gradient',
38000
+ 'repeating-linear-gradient',
38001
+ 'radial-gradient',
38002
+ 'repeating-radial-gradient',
38003
+ 'conic-gradient',
38004
+ 'repeating-conic-gradient',
38005
+ 'url'
38006
+ ];
38007
+ /**
38008
+ * Adds background CSS styles processing rules to the given `StylesProcessor`.
38009
+ *
38010
+ * Registers normalizers for the `background` shorthand and its longhand properties,
38011
+ * reducers that serialize them back to CSS strings, and the relation mapping between them.
37928
38012
  *
37929
38013
  * ```ts
37930
38014
  * editor.data.addStyleProcessorRules( addBackgroundStylesRules );
37931
38015
  * ```
37932
38016
  *
37933
- * The normalized value is stored as:
37934
- *
37935
- * ```ts
37936
- * const styles = {
37937
- * background: {
37938
- * color,
37939
- * repeat,
37940
- * position,
37941
- * attachment,
37942
- * image
37943
- * }
37944
- * };
37945
- * ````
37946
- *
37947
- * **Note**: Currently only `'background-color'` longhand value is parsed besides `'background'` shorthand. The reducer also supports only
37948
- * `'background-color'` value.
38017
+ * @param stylesProcessor The styles processor instance to register rules on.
37949
38018
  */ function addBackgroundStylesRules(stylesProcessor) {
37950
- stylesProcessor.setNormalizer('background', getBackgroundNormalizer());
37951
38019
  stylesProcessor.setNormalizer('background-color', getBackgroundColorNormalizer());
38020
+ for(const property in BACKGROUND_INITIAL_ARRAY_VALUES){
38021
+ stylesProcessor.setNormalizer(`background-${property}`, getBackgroundArrayPropertyNormalizer(`background.${property}`));
38022
+ stylesProcessor.setReducer(`background-${property}`, getBackgroundArrayPropertyReducer(`background-${property}`));
38023
+ }
38024
+ // Normalized data format:
38025
+ // {
38026
+ // color: 'red',
38027
+ // image: [ 'url(img1.png)', 'url(img2.png)' ],
38028
+ // position: [ '0% 0%', '50% 50%' ],
38029
+ // repeat: [ 'no-repeat', 'repeat' ],
38030
+ // // ...
38031
+ // }
38032
+ stylesProcessor.setNormalizer('background', getBackgroundNormalizer());
37952
38033
  stylesProcessor.setReducer('background', getBackgroundReducer());
37953
38034
  stylesProcessor.setStyleRelation('background', [
37954
- 'background-color'
38035
+ 'background-color',
38036
+ 'background-image',
38037
+ 'background-repeat',
38038
+ 'background-position',
38039
+ 'background-size',
38040
+ 'background-attachment',
38041
+ 'background-origin',
38042
+ 'background-clip'
37955
38043
  ]);
37956
38044
  }
37957
- function getBackgroundNormalizer() {
38045
+ /**
38046
+ * Returns a normalizer for the `background` shorthand property.
38047
+ *
38048
+ * Parses the raw CSS value into comma-separated layers and merges them into
38049
+ * a structured `Background` object stored under the `background` path.
38050
+ */ function getBackgroundNormalizer() {
37958
38051
  return (value)=>{
37959
- const background = {};
37960
- const parts = getShorthandStylesValues(value);
37961
- for (const part of parts){
37962
- if (isRepeatStyleValue(part)) {
37963
- background.repeat = background.repeat || [];
37964
- background.repeat.push(part);
37965
- } else if (isPositionStyleValue(part)) {
37966
- background.position = background.position || [];
37967
- background.position.push(part);
37968
- } else if (isAttachmentStyleValue(part)) {
37969
- background.attachment = part;
37970
- } else if (isColorStyleValue(part)) {
37971
- background.color = part;
37972
- } else if (isURLStyleValue(part)) {
37973
- background.image = part;
37974
- }
38052
+ const layers = parseBackgroundIntoLayers(value);
38053
+ // If for some reason, it was impossible to extract any valid layers from the input,
38054
+ // assume it's color value for a single layer background, as it's the most common use
38055
+ // case and better than losing the value completely.
38056
+ if (!layers.length) {
38057
+ layers.push({
38058
+ ...getDefaultBackgroundLayer(),
38059
+ color: value
38060
+ });
37975
38061
  }
38062
+ const background = normalizeBackgroundLayers(layers);
37976
38063
  return {
37977
38064
  path: 'background',
37978
38065
  value: background
37979
38066
  };
37980
38067
  };
37981
38068
  }
37982
- function getBackgroundColorNormalizer() {
38069
+ /**
38070
+ * Returns a normalizer for the `background-color` longhand property.
38071
+ *
38072
+ * Stores the raw color value directly under the `background.color` path.
38073
+ */ function getBackgroundColorNormalizer() {
37983
38074
  return (value)=>({
37984
38075
  path: 'background.color',
37985
38076
  value
37986
38077
  });
37987
38078
  }
37988
- function getBackgroundReducer() {
38079
+ /**
38080
+ * Returns a normalizer for a comma-separated background array longhand property
38081
+ * (e.g. `background-image`, `background-repeat`, `background-position`, `background-attachment`).
38082
+ *
38083
+ * Splits the raw value by top-level commas and stores the resulting array under the given path.
38084
+ *
38085
+ * @param path The target style path, e.g. `'background.image'`.
38086
+ */ function getBackgroundArrayPropertyNormalizer(path) {
38087
+ return (value)=>({
38088
+ path,
38089
+ value: splitByTopLevelCommas(value)
38090
+ });
38091
+ }
38092
+ /**
38093
+ * Returns a reducer for a comma-separated background array longhand property
38094
+ * (e.g. `background-image`, `background-repeat`, `background-position`, `background-attachment`).
38095
+ *
38096
+ * Serializes an array of per-layer values back into a comma-separated CSS string.
38097
+ *
38098
+ * @param property The CSS property name to output, e.g. `'background-image'`.
38099
+ */ function getBackgroundArrayPropertyReducer(property) {
37989
38100
  return (value)=>{
37990
- const ret = [];
37991
- ret.push([
38101
+ const serialized = value.join(', ');
38102
+ return [
38103
+ [
38104
+ property,
38105
+ serialized
38106
+ ]
38107
+ ];
38108
+ };
38109
+ }
38110
+ /**
38111
+ * Returns a reducer for the `background` property. Depending on which longhand properties are present, it either:
38112
+ *
38113
+ * * Serializes into a concise `background` shorthand if all required longhand properties are present and non-empty, or
38114
+ * * Serializes into individual longhand properties for those that have defined values.
38115
+ *
38116
+ * This prevents overwriting external stylesheet rules with default values that were not explicitly set in the model.
38117
+ * For example, if only `background-color` is defined in the model, we emit just `background-color` rather than
38118
+ * the full `background` shorthand, which would reset all other sub-properties to their initial values.
38119
+ */ function getBackgroundReducer() {
38120
+ return (value)=>{
38121
+ const background = value;
38122
+ // It is highly unlikely that all of these properties were set manually. If all fields are present,
38123
+ // they were most likely populated by parsing the `background` shorthand, which fills all of them
38124
+ // for every layer. In this case, we can safely serialize back to the `background` shorthand.
38125
+ // On the other hand, if some fields are missing, it means the background was created by manually
38126
+ // setting individual longhand properties (e.g., `background-origin`, `background-attachment`, etc.).
38127
+ // We should preserve that intent and serialize to longhands to prevent emitting default values
38128
+ // for the missing properties.
38129
+ const allFieldsLayersFilled = Object.keys(BACKGROUND_INITIAL_ARRAY_VALUES).every((key)=>{
38130
+ const value = background[key];
38131
+ return value !== undefined && (!Array.isArray(value) || value.length > 0);
38132
+ });
38133
+ if (allFieldsLayersFilled) {
38134
+ return serializeToShorthandBackground(background);
38135
+ }
38136
+ return serializeToLonghandBackground(background);
38137
+ };
38138
+ }
38139
+ /**
38140
+ * Serializes a structured `Background` object into a concise CSS `background` shorthand string.
38141
+ */ function serializeToShorthandBackground(background) {
38142
+ const result = [];
38143
+ const shorthand = extractBackgroundLayers(background).map((layer)=>serializeBackgroundLayer(layer).trim()).filter(Boolean).join(', ');
38144
+ if (shorthand) {
38145
+ result.push([
38146
+ 'background',
38147
+ shorthand
38148
+ ]);
38149
+ }
38150
+ return result;
38151
+ }
38152
+ /**
38153
+ * Serializes a structured `Background` object into individual CSS longhand properties for those that have defined values.
38154
+ * Each longhand property is serialized into a comma-separated string of per-layer values.
38155
+ *
38156
+ * This is used when not all required longhand properties are present, to avoid emitting default values for missing properties
38157
+ * and potentially overwriting external stylesheet rules.
38158
+ */ function serializeToLonghandBackground(background) {
38159
+ const result = [];
38160
+ for(const key in BACKGROUND_INITIAL_ARRAY_VALUES){
38161
+ const value = background[key];
38162
+ if (Array.isArray(value)) {
38163
+ result.push([
38164
+ `background-${key}`,
38165
+ value.join(', ')
38166
+ ]);
38167
+ }
38168
+ }
38169
+ if (background.color !== undefined) {
38170
+ result.push([
37992
38171
  'background-color',
37993
- value.color
38172
+ background.color
37994
38173
  ]);
37995
- return ret;
38174
+ }
38175
+ return result;
38176
+ }
38177
+ /**
38178
+ * Serializes a single `BackgroundLayer` into a CSS background layer string.
38179
+ * Properties equal to their CSS initial values are omitted.
38180
+ *
38181
+ * @param layer A single background layer to serialize.
38182
+ * @returns A space-separated CSS string for the layer, or an empty string if no parts are present.
38183
+ */ function serializeBackgroundLayer(layer) {
38184
+ const parts = [];
38185
+ if (layer.image && layer.image !== BACKGROUND_INITIAL_ARRAY_VALUES.image) {
38186
+ parts.push(layer.image);
38187
+ }
38188
+ const positionStr = layer.position.join(' ');
38189
+ const isPositionDefault = !positionStr || positionStr === BACKGROUND_INITIAL_ARRAY_VALUES.position;
38190
+ if (!isPositionDefault) {
38191
+ parts.push(positionStr);
38192
+ }
38193
+ const sizeStr = layer.size.join(' ');
38194
+ const isSizeDefault = !sizeStr || sizeStr === BACKGROUND_INITIAL_ARRAY_VALUES.size;
38195
+ if (!isSizeDefault) {
38196
+ if (isPositionDefault) {
38197
+ parts.push('0% 0%');
38198
+ }
38199
+ parts.push('/', sizeStr);
38200
+ }
38201
+ const repeatStr = layer.repeat.join(' ');
38202
+ if (repeatStr && repeatStr !== BACKGROUND_INITIAL_ARRAY_VALUES.repeat) {
38203
+ parts.push(repeatStr);
38204
+ }
38205
+ if (layer.attachment && layer.attachment !== BACKGROUND_INITIAL_ARRAY_VALUES.attachment) {
38206
+ parts.push(layer.attachment);
38207
+ }
38208
+ const isOriginDefault = layer.origin === BACKGROUND_INITIAL_ARRAY_VALUES.origin;
38209
+ const isClipDefault = layer.clip === BACKGROUND_INITIAL_ARRAY_VALUES.clip;
38210
+ if (!isOriginDefault || !isClipDefault) {
38211
+ parts.push(layer.origin);
38212
+ if (layer.clip !== layer.origin) {
38213
+ parts.push(layer.clip);
38214
+ }
38215
+ }
38216
+ if (layer.color) {
38217
+ parts.push(layer.color);
38218
+ }
38219
+ return parts.join(' ');
38220
+ }
38221
+ /**
38222
+ * Splits a structured `Background` object into an array of individual `BackgroundLayer` objects.
38223
+ *
38224
+ * The number of layers is determined by the longest array among the longhand properties.
38225
+ * The `color` value, if present, is always assigned to the last layer (per CSS spec).
38226
+ *
38227
+ * @param background The structured background object to split.
38228
+ * @returns An array of per-layer background objects.
38229
+ *
38230
+ * @example
38231
+ * // Input: { image: [ 'url(a.png)', 'url(b.png)' ], repeat: [ 'no-repeat', 'repeat' ], color: 'blue' }
38232
+ * // Output: [
38233
+ * // { image: 'url(a.png)', repeat: [ 'no-repeat' ] },
38234
+ * // { image: 'url(b.png)', repeat: [ 'repeat' ], color: 'blue' }
38235
+ * // ]
38236
+ */ function extractBackgroundLayers(background) {
38237
+ const layerCount = getTotalBackgroundLayers(background);
38238
+ const layers = Array.from({
38239
+ length: layerCount
38240
+ }, (_, i)=>{
38241
+ const layer = getDefaultBackgroundLayer();
38242
+ if (background.image?.[i]) {
38243
+ layer.image = background.image[i];
38244
+ }
38245
+ if (background.position?.[i]) {
38246
+ layer.position = background.position[i].split(' ');
38247
+ }
38248
+ if (background.size?.[i]) {
38249
+ layer.size = background.size[i].split(' ');
38250
+ }
38251
+ if (background.repeat?.[i]) {
38252
+ layer.repeat = background.repeat[i].split(' ');
38253
+ }
38254
+ if (background.attachment?.[i]) {
38255
+ layer.attachment = background.attachment[i];
38256
+ }
38257
+ if (background.origin?.[i]) {
38258
+ layer.origin = background.origin[i];
38259
+ }
38260
+ if (background.clip?.[i]) {
38261
+ layer.clip = background.clip[i];
38262
+ }
38263
+ return layer;
38264
+ });
38265
+ if (background.color) {
38266
+ // According to standard, the last layer can contain the color definition,
38267
+ // so we set it on the last layer if it exists.
38268
+ layers.at(-1).color = background.color;
38269
+ }
38270
+ return layers;
38271
+ }
38272
+ /**
38273
+ * Determines the total number of background layers based on the longest array among the longhand properties in the `Background` object.
38274
+ *
38275
+ * @param background The structured background object to analyze.
38276
+ * @returns The total number of layers, which is the maximum length among the longhand property arrays.
38277
+ */ function getTotalBackgroundLayers(background) {
38278
+ let layersCount = 0;
38279
+ for (const value of Object.values(background)){
38280
+ if (Array.isArray(value) && value.length > layersCount) {
38281
+ layersCount = value.length;
38282
+ }
38283
+ }
38284
+ return layersCount;
38285
+ }
38286
+ /**
38287
+ * Merges an array of `BackgroundLayer` objects into a single structured `Background` object,
38288
+ * storing each longhand property as an array of per-layer values.
38289
+ *
38290
+ * Each input layer always has all properties defined (via `getDefaultBackgroundLayer`),
38291
+ * so the resulting arrays are fully populated for every layer.
38292
+ *
38293
+ * @param layers An array of parsed background layers.
38294
+ * @returns A merged `Background` object.
38295
+ *
38296
+ * @example
38297
+ * // Input: [ { image: 'url(a.png)', repeat: [ 'no-repeat' ], position: [ '0%', '0%' ], ... }, { image: 'none', color: 'red', ... } ]
38298
+ * // Output: {
38299
+ * // image: [ 'url(a.png)', 'none' ],
38300
+ * // position: [ '0% 0%', '0% 0%' ],
38301
+ * // repeat: [ 'no-repeat', 'repeat' ],
38302
+ * // ...
38303
+ * // color: 'red'
38304
+ * // }
38305
+ */ function normalizeBackgroundLayers(layers) {
38306
+ const background = {
38307
+ image: [],
38308
+ position: [],
38309
+ size: [],
38310
+ repeat: [],
38311
+ attachment: [],
38312
+ origin: [],
38313
+ clip: []
38314
+ };
38315
+ for (const layer of layers){
38316
+ background.position.push(layer.position.join(' '));
38317
+ background.size.push(layer.size.join(' '));
38318
+ background.repeat.push(layer.repeat.join(' '));
38319
+ background.image.push(layer.image);
38320
+ background.attachment.push(layer.attachment);
38321
+ background.origin.push(layer.origin);
38322
+ background.clip.push(layer.clip);
38323
+ }
38324
+ if (layers.at(-1)?.color) {
38325
+ background.color = layers.at(-1).color;
38326
+ }
38327
+ return background;
38328
+ }
38329
+ /**
38330
+ * Parses a raw CSS `background` value and splits it into an array of `BackgroundLayer` objects,
38331
+ * one per comma-separated layer.
38332
+ *
38333
+ * The CSS `background` shorthand syntax is:
38334
+ * `background: [ <bg-layer> , ]* <final-bg-layer>`
38335
+ *
38336
+ * Commas inside function calls (e.g. `rgba()`, `linear-gradient()`) are correctly ignored
38337
+ * during splitting.
38338
+ *
38339
+ * @param value The raw CSS background value string.
38340
+ * @returns An array of parsed background layers.
38341
+ *
38342
+ * @example
38343
+ * splitBackgroundIntoLayers( 'url(a.png) no-repeat, red' );
38344
+ * // → [ { image: 'url(a.png)', repeat: [ 'no-repeat' ] }, { color: 'red' } ]
38345
+ */ function parseBackgroundIntoLayers(value) {
38346
+ return splitByTopLevelCommas(value).map(parseBackgroundLayer).filter((obj)=>obj !== null);
38347
+ }
38348
+ /**
38349
+ * Parses a single CSS background layer string into a structured `BackgroundLayer` object.
38350
+ *
38351
+ * First extracts any image function (gradient or `url()`), then classifies the remaining
38352
+ * space-separated tokens as repeat, position, attachment, or color values.
38353
+ *
38354
+ * @param layer A single (non-comma-separated) background layer string.
38355
+ * @returns A structured background layer object. If no valid properties were found, returns `null`.
38356
+ *
38357
+ * @example
38358
+ * parseBackgroundLayer( 'url(bg.png) top left no-repeat fixed' );
38359
+ * // → { image: 'url(bg.png)', position: [ 'top', 'left' ], repeat: [ 'no-repeat' ], attachment: 'fixed' }
38360
+ */ function parseBackgroundLayer(layer) {
38361
+ const background = {};
38362
+ const { value: valueWithoutImage, image } = extractBackgroundImage(layer);
38363
+ const parts = getShorthandStylesValues(valueWithoutImage);
38364
+ if (image) {
38365
+ background.image = image;
38366
+ }
38367
+ for(let i = 0; i < parts.length; i++){
38368
+ const part = parts[i];
38369
+ if (part === '/') {
38370
+ background.size = [];
38371
+ while(i + 1 < parts.length && isSizeStyleValue(parts[i + 1])){
38372
+ background.size.push(parts[++i]);
38373
+ }
38374
+ } else if (isRepeatStyleValue(part)) {
38375
+ background.repeat ||= [];
38376
+ background.repeat.push(part);
38377
+ } else if (isPositionStyleValue(part) || isPercentageStyleValue(part)) {
38378
+ background.position ||= [];
38379
+ background.position.push(part);
38380
+ // Percentage positions can be paired (e.g. '0% 0%'), so consume the next token if it's also a percentage.
38381
+ if (i + 1 < parts.length && isPercentageStyleValue(part) && isPercentageStyleValue(parts[i + 1])) {
38382
+ background.position.push(parts[++i]);
38383
+ }
38384
+ } else if (isAttachmentStyleValue(part)) {
38385
+ background.attachment = part;
38386
+ } else if (isClipStyleValue(part)) {
38387
+ if (isOriginStyleValue(part) && !background.origin) {
38388
+ // First box value sets both origin and clip (per CSS spec).
38389
+ background.origin = part;
38390
+ background.clip = part;
38391
+ } else {
38392
+ // Second box value (or 'text') sets only clip.
38393
+ background.clip = part;
38394
+ }
38395
+ } else if (isColorStyleValue(part)) {
38396
+ background.color = part;
38397
+ }
38398
+ }
38399
+ if (isEmpty(background)) {
38400
+ return null;
38401
+ }
38402
+ return {
38403
+ ...getDefaultBackgroundLayer(),
38404
+ ...background
38405
+ };
38406
+ }
38407
+ /**
38408
+ * Returns a `BackgroundLayer` object with all properties set to their CSS initial values.
38409
+ *
38410
+ * Used as the base when parsing the `background` shorthand so that every property of a parsed
38411
+ * layer always has a defined value.
38412
+ *
38413
+ * @returns A background layer with default values.
38414
+ */ function getDefaultBackgroundLayer() {
38415
+ return {
38416
+ attachment: BACKGROUND_INITIAL_ARRAY_VALUES.attachment,
38417
+ image: BACKGROUND_INITIAL_ARRAY_VALUES.image,
38418
+ origin: BACKGROUND_INITIAL_ARRAY_VALUES.origin,
38419
+ clip: BACKGROUND_INITIAL_ARRAY_VALUES.clip,
38420
+ position: BACKGROUND_INITIAL_ARRAY_VALUES.position.split(' '),
38421
+ repeat: BACKGROUND_INITIAL_ARRAY_VALUES.repeat.split(' '),
38422
+ size: BACKGROUND_INITIAL_ARRAY_VALUES.size.split(' ')
38423
+ };
38424
+ }
38425
+ /**
38426
+ * Extracts the first CSS image function (`linear-gradient`, `url`, etc.) from a raw CSS value string
38427
+ * and returns it separately along with the remaining string with the image function removed.
38428
+ *
38429
+ * Handles arbitrarily nested parentheses correctly (e.g. `rgba()` inside a gradient).
38430
+ * Only one image function is extracted per call — the caller is responsible for looping
38431
+ * if multiple image functions may be present.
38432
+ *
38433
+ * @param value The raw CSS value string to process.
38434
+ * @returns An object with `value` (the string with the image function removed) and
38435
+ * `image` (the extracted function string, or `null` if none was found).
38436
+ *
38437
+ * @example
38438
+ * extractBackgroundImage( 'linear-gradient(red, blue) no-repeat' );
38439
+ * // → { value: ' no-repeat', image: 'linear-gradient(red, blue)' }
38440
+ */ function extractBackgroundImage(value) {
38441
+ for (const imageFunction of IMAGE_FUNCTIONS){
38442
+ const prefix = imageFunction + '(';
38443
+ const firstIndex = value.indexOf(prefix);
38444
+ if (firstIndex < 0) {
38445
+ continue;
38446
+ }
38447
+ let acc = imageFunction;
38448
+ let nesting = 0;
38449
+ for(let i = firstIndex + imageFunction.length; i < value.length; i++){
38450
+ const char = value[i];
38451
+ if (char === '(') {
38452
+ nesting++;
38453
+ } else if (char === ')') {
38454
+ nesting--;
38455
+ }
38456
+ acc += char;
38457
+ if (nesting === 0) {
38458
+ return {
38459
+ value: value.slice(0, firstIndex) + value.slice(i + 1),
38460
+ image: acc
38461
+ };
38462
+ }
38463
+ }
38464
+ }
38465
+ // If no image functions were found, check if the value contains 'none', which is also a valid background-image value.
38466
+ if (value.includes('none')) {
38467
+ return {
38468
+ value: value.replace('none', ''),
38469
+ image: 'none'
38470
+ };
38471
+ }
38472
+ return {
38473
+ value,
38474
+ image: null
37996
38475
  };
37997
38476
  }
38477
+ /**
38478
+ * Splits a CSS value string by commas that are at the top level (i.e. not inside parentheses).
38479
+ *
38480
+ * This is necessary because commas appear both as layer separators in the `background` shorthand
38481
+ * and as argument separators inside functions like `rgba()` or `linear-gradient()`.
38482
+ *
38483
+ * @param value The CSS value string to split.
38484
+ * @returns An array of trimmed top-level comma-separated segments.
38485
+ *
38486
+ * @example
38487
+ * splitByTopLevelCommas( 'linear-gradient(red, blue), center' );
38488
+ * // → [ 'linear-gradient(red, blue)', 'center' ]
38489
+ */ function splitByTopLevelCommas(value) {
38490
+ const parts = [];
38491
+ let current = '';
38492
+ let nesting = 0;
38493
+ for (const char of value){
38494
+ if (char === '(') {
38495
+ nesting++;
38496
+ } else if (char === ')') {
38497
+ nesting--;
38498
+ } else if (char === ',' && nesting === 0) {
38499
+ parts.push(current.trim());
38500
+ current = '';
38501
+ continue;
38502
+ }
38503
+ current += char;
38504
+ }
38505
+ if (current.trim()) {
38506
+ parts.push(current.trim());
38507
+ }
38508
+ return parts;
38509
+ }
37998
38510
 
37999
38511
  /**
38000
38512
  * Adds a border CSS styles processing rules.
@@ -38017,19 +38529,13 @@ function getBackgroundReducer() {
38017
38529
  * and all corresponding longhand forms (like `border-top-color`, `border-top-style`, etc).
38018
38530
  *
38019
38531
  * It does not handle other shorthands (like `border-radius` or `border-image`).
38020
- *
38021
- * The normalized model stores border values as:
38022
- *
38023
- * ```ts
38024
- * const styles = {
38025
- * border: {
38026
- * color: { top, right, bottom, left },
38027
- * style: { top, right, bottom, left },
38028
- * width: { top, right, bottom, left },
38029
- * }
38030
- * };
38031
- * ```
38032
38532
  */ function addBorderStylesRules(stylesProcessor) {
38533
+ // Normalized data format:
38534
+ // {
38535
+ // color: { top: 'red', right: 'red', bottom: 'red', left: 'red' },
38536
+ // style: { top: 'solid', right: 'solid', bottom: 'solid', left: 'solid' },
38537
+ // width: { top: '1px', right: '1px', bottom: '1px', left: '1px' }
38538
+ // }
38033
38539
  stylesProcessor.setNormalizer('border', getBorderNormalizer());
38034
38540
  // Border-position shorthands.
38035
38541
  stylesProcessor.setNormalizer('border-top', getBorderPositionNormalizer('top'));
@@ -38368,20 +38874,14 @@ function getBorderPositionReducer(which) {
38368
38874
  * ```ts
38369
38875
  * editor.data.addStyleProcessorRules( addMarginStylesRules );
38370
38876
  * ```
38371
- *
38372
- * The normalized value is stored as:
38373
- *
38374
- * ```ts
38375
- * const styles = {
38376
- * margin: {
38377
- * top,
38378
- * right,
38379
- * bottom,
38380
- * left
38381
- * }
38382
- * };
38383
- * ```
38384
38877
  */ function addMarginStylesRules(stylesProcessor) {
38878
+ // Normalized data format:
38879
+ // {
38880
+ // top: '1px',
38881
+ // right: '2px',
38882
+ // bottom: '3px',
38883
+ // left: '4px'
38884
+ // }
38385
38885
  stylesProcessor.setNormalizer('margin', getPositionStyleShorthandNormalizer('margin'));
38386
38886
  stylesProcessor.setNormalizer('margin-top', (value)=>({
38387
38887
  path: 'margin.top',
@@ -38414,20 +38914,14 @@ function getBorderPositionReducer(which) {
38414
38914
  * ```ts
38415
38915
  * editor.data.addStyleProcessorRules( addPaddingStylesRules );
38416
38916
  * ```
38417
- *
38418
- * The normalized value is stored as:
38419
- *
38420
- * ```ts
38421
- * const styles = {
38422
- * padding: {
38423
- * top,
38424
- * right,
38425
- * bottom,
38426
- * left
38427
- * }
38428
- * };
38429
- * ```
38430
38917
  */ function addPaddingStylesRules(stylesProcessor) {
38918
+ // Normalized data format:
38919
+ // {
38920
+ // top: '1px',
38921
+ // right: '2px',
38922
+ // bottom: '3px',
38923
+ // left: '4px'
38924
+ // }
38431
38925
  stylesProcessor.setNormalizer('padding', getPositionStyleShorthandNormalizer('padding'));
38432
38926
  stylesProcessor.setNormalizer('padding-top', (value)=>({
38433
38927
  path: 'padding.top',
@@ -39983,5 +40477,5 @@ const maxTreeDumpLength = 20;
39983
40477
  }
39984
40478
  }
39985
40479
 
39986
- export { AttributeOperation, Batch, BubblingEmitterMixin, BubblingEventInfo, ClickObserver, CompositionObserver, Conversion, ConversionHelpers, DataController, Differ, DomEventObserver, DowncastHelpers, EditingController, EditingView, FakeSelectionObserver, FocusObserver, History, HtmlDataProcessor, InputObserver, InsertOperation, KeyObserver, Mapper, MarkerCollection, MarkerOperation, Matcher, MergeOperation, Model, ModelDocument, ModelDocumentFragment, ModelDocumentSelection, ModelElement, ModelLivePosition, ModelLiveRange, ModelNode, ModelNodeList, ModelPosition, ModelRange, ModelRootElement, ModelSchema, ModelSchemaContext, ModelSelection, ModelText, ModelTextProxy, ModelTreeWalker, ModelTypeCheckable, ModelWriter, MouseObserver, MoveOperation, MutationObserver, NoOperation, Observer, OperationFactory, PointerObserver, RenameOperation, RootAttributeOperation, RootOperation, SelectionObserver, SplitOperation, StylesMap, StylesProcessor, TabObserver, TouchObserver, UpcastHelpers, ViewUpcastWriter as UpcastWriter, ViewAttributeElement, ViewContainerElement, ViewDataTransfer, ViewDocument, ViewDocumentDomEventData, ViewDocumentFragment, ViewDocumentSelection, ViewDomConverter, ViewDowncastWriter, ViewEditableElement, ViewElement, ViewEmptyElement, ViewNode, ViewPosition, ViewRange, ViewRawElement, ViewRenderer, ViewRootEditableElement, ViewSelection, ViewText, ViewTextProxy, ViewTokenList, ViewTreeWalker, ViewTypeCheckable, ViewUIElement, ViewUpcastWriter, XmlDataProcessor, BasicHtmlWriter as _DataProcessorBasicHtmlWriter, DetachOperation as _DetachOperation, MapperCache as _MapperCache, OperationReplayer as _OperationReplayer, BR_FILLER as _VIEW_BR_FILLER, INLINE_FILLER as _VIEW_INLINE_FILLER, INLINE_FILLER_LENGTH as _VIEW_INLINE_FILLER_LENGTH, MARKED_NBSP_FILLER as _VIEW_MARKED_NBSP_FILLER, NBSP_FILLER as _VIEW_NBSP_FILLER, ViewElementConsumables as _ViewElementConversionConsumables, autoParagraphEmptyRoots as _autoParagraphEmptyModelRoots, convertMapToStringifiedObject as _convertMapToStringifiedObject, convertMapToTags as _convertMapToTags, deleteContent as _deleteModelContent, cleanSelection as _downcastCleanSelection, convertCollapsedSelection as _downcastConvertCollapsedSelection, convertRangeSelection as _downcastConvertRangeSelection, createViewElementFromDowncastHighlightDescriptor as _downcastCreateViewElementFromDowncastHighlightDescriptor, insertAttributesAndChildren as _downcastInsertAttributesAndChildren, insertElement as _downcastInsertElement, insertStructure as _downcastInsertStructure, insertText as _downcastInsertText, insertUIElement as _downcastInsertUIElement, remove as _downcastRemove, wrap as _downcastWrap, dumpTrees as _dumpTrees, getDataWithoutFiller as _getDataWithoutViewFiller, _getModelData, getNodeAfterPosition as _getModelNodeAfterPosition, getNodeBeforePosition as _getModelNodeBeforePosition, getTextNodeAtPosition as _getModelTextNodeAtPosition, getSelectedContent as _getSelectedModelContent, _getViewData, initDocumentDumping as _initDocumentDumping, injectSelectionPostFixer as _injectModelSelectionPostFixer, injectQuirksHandling as _injectViewQuirksHandling, injectUiElementHandling as _injectViewUIElementHandling, _insert as _insertIntoModelNodeList, insertContent as _insertModelContent, insertObject as _insertModelObject, isInlineFiller as _isInlineViewFiller, isParagraphable as _isParagraphableModelNode, isPatternMatched as _isViewPatternMatched, logDocument as _logDocument, mergeIntersectingRanges as _mergeIntersectingModelRanges, modifySelection as _modifyModelSelection, _move as _moveInModelNodeList, normalizeConsumables as _normalizeConversionConsumables, _normalizeNodes as _normalizeInModelNodeList, transform$1 as _operationTransform, _parseModel, _parseView, _remove as _removeFromModelNodeList, _setAttribute as _setAttributeInModelNodeList, _setModelData, _setViewData, startsWithFiller as _startsWithViewFiller, _stringifyModel, _stringifyView, tryFixingRange as _tryFixingModelRange, convertSelectionChange as _upcastConvertSelectionChange, convertText as _upcastConvertText, convertToModelFragment$1 as _upcastConvertToModelFragment, wrapInParagraph as _wrapInModelParagraph, addBackgroundStylesRules, addBorderStylesRules, addMarginStylesRules, addPaddingStylesRules, autoParagraphEmptyRoots, disableViewPlaceholder, enableViewPlaceholder, getBoxSidesStyleShorthandValue, getBoxSidesStyleValueReducer, getBoxSidesStyleValues, getPositionStyleShorthandNormalizer, getShorthandStylesValues, getViewFillerOffset, hideViewPlaceholder, isAttachmentStyleValue, isColorStyleValue, isLengthStyleValue, isLineStyleValue, isParagraphable, isPercentageStyleValue, isPositionStyleValue, isRepeatStyleValue, isURLStyleValue, needsViewPlaceholder, showViewPlaceholder, transformOperationSets, wrapInParagraph };
40480
+ export { AttributeOperation, Batch, BubblingEmitterMixin, BubblingEventInfo, ClickObserver, CompositionObserver, Conversion, ConversionHelpers, DataController, Differ, DomEventObserver, DowncastHelpers, EditingController, EditingView, FakeSelectionObserver, FocusObserver, History, HtmlDataProcessor, InputObserver, InsertOperation, KeyObserver, Mapper, MarkerCollection, MarkerOperation, Matcher, MergeOperation, Model, ModelDocument, ModelDocumentFragment, ModelDocumentSelection, ModelElement, ModelLivePosition, ModelLiveRange, ModelNode, ModelNodeList, ModelPosition, ModelRange, ModelRootElement, ModelSchema, ModelSchemaContext, ModelSelection, ModelText, ModelTextProxy, ModelTreeWalker, ModelTypeCheckable, ModelWriter, MouseObserver, MoveOperation, MutationObserver, NoOperation, Observer, OperationFactory, PointerObserver, RenameOperation, RootAttributeOperation, RootOperation, SelectionObserver, SplitOperation, StylesMap, StylesProcessor, TabObserver, TouchObserver, UpcastHelpers, ViewUpcastWriter as UpcastWriter, ViewAttributeElement, ViewContainerElement, ViewDataTransfer, ViewDocument, ViewDocumentDomEventData, ViewDocumentFragment, ViewDocumentSelection, ViewDomConverter, ViewDowncastWriter, ViewEditableElement, ViewElement, ViewEmptyElement, ViewNode, ViewPosition, ViewRange, ViewRawElement, ViewRenderer, ViewRootEditableElement, ViewSelection, ViewText, ViewTextProxy, ViewTokenList, ViewTreeWalker, ViewTypeCheckable, ViewUIElement, ViewUpcastWriter, XmlDataProcessor, BasicHtmlWriter as _DataProcessorBasicHtmlWriter, DetachOperation as _DetachOperation, MapperCache as _MapperCache, OperationReplayer as _OperationReplayer, BR_FILLER as _VIEW_BR_FILLER, INLINE_FILLER as _VIEW_INLINE_FILLER, INLINE_FILLER_LENGTH as _VIEW_INLINE_FILLER_LENGTH, MARKED_NBSP_FILLER as _VIEW_MARKED_NBSP_FILLER, NBSP_FILLER as _VIEW_NBSP_FILLER, ViewElementConsumables as _ViewElementConversionConsumables, autoParagraphEmptyRoots as _autoParagraphEmptyModelRoots, convertMapToStringifiedObject as _convertMapToStringifiedObject, convertMapToTags as _convertMapToTags, deleteContent as _deleteModelContent, cleanSelection as _downcastCleanSelection, convertCollapsedSelection as _downcastConvertCollapsedSelection, convertRangeSelection as _downcastConvertRangeSelection, createViewElementFromDowncastHighlightDescriptor as _downcastCreateViewElementFromDowncastHighlightDescriptor, insertAttributesAndChildren as _downcastInsertAttributesAndChildren, insertElement as _downcastInsertElement, insertStructure as _downcastInsertStructure, insertText as _downcastInsertText, insertUIElement as _downcastInsertUIElement, remove as _downcastRemove, wrap as _downcastWrap, dumpTrees as _dumpTrees, getDataWithoutFiller as _getDataWithoutViewFiller, _getModelData, getNodeAfterPosition as _getModelNodeAfterPosition, getNodeBeforePosition as _getModelNodeBeforePosition, getTextNodeAtPosition as _getModelTextNodeAtPosition, getSelectedContent as _getSelectedModelContent, _getViewData, initDocumentDumping as _initDocumentDumping, injectSelectionPostFixer as _injectModelSelectionPostFixer, injectQuirksHandling as _injectViewQuirksHandling, injectUiElementHandling as _injectViewUIElementHandling, _insert as _insertIntoModelNodeList, insertContent as _insertModelContent, insertObject as _insertModelObject, isInlineFiller as _isInlineViewFiller, isParagraphable as _isParagraphableModelNode, isPatternMatched as _isViewPatternMatched, logDocument as _logDocument, mergeIntersectingRanges as _mergeIntersectingModelRanges, modifySelection as _modifyModelSelection, _move as _moveInModelNodeList, normalizeConsumables as _normalizeConversionConsumables, _normalizeNodes as _normalizeInModelNodeList, transform$1 as _operationTransform, _parseModel, _parseView, _remove as _removeFromModelNodeList, _setAttribute as _setAttributeInModelNodeList, _setModelData, _setViewData, startsWithFiller as _startsWithViewFiller, _stringifyModel, _stringifyView, tryFixingRange as _tryFixingModelRange, convertSelectionChange as _upcastConvertSelectionChange, convertText as _upcastConvertText, convertToModelFragment$1 as _upcastConvertToModelFragment, wrapInParagraph as _wrapInModelParagraph, addBackgroundStylesRules, addBorderStylesRules, addMarginStylesRules, addPaddingStylesRules, disableViewPlaceholder, enableViewPlaceholder, getBoxSidesStyleShorthandValue, getBoxSidesStyleValueReducer, getBoxSidesStyleValues, getPositionStyleShorthandNormalizer, getShorthandStylesValues, getViewFillerOffset, hideViewPlaceholder, isAttachmentStyleValue, isColorStyleValue, isLengthStyleValue, isLineStyleValue, isPercentageStyleValue, isPositionStyleValue, isRepeatStyleValue, isURLStyleValue, needsViewPlaceholder, showViewPlaceholder, transformOperationSets };
39987
40481
  //# sourceMappingURL=index.js.map