roosterjs 9.51.0 → 9.53.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.
@@ -9056,9 +9056,12 @@ function getContentForCopy(editor, isCut, event) {
9056
9056
  rawEvent: event,
9057
9057
  isCut: isCut,
9058
9058
  }).clonedRoot;
9059
+ // Build the text content from the (possibly modified) cloned root DOM tree so that any
9060
+ // changes made by beforeCutCopy event handlers are reflected in the plain text result as well
9061
+ var textModel = (0, roosterjs_content_model_dom_1.domToContentModel)(clonedRoot, (0, roosterjs_content_model_dom_1.createDomToModelContext)());
9059
9062
  return {
9060
9063
  htmlContent: clonedRoot,
9061
- textContent: (0, roosterjs_content_model_dom_1.contentModelToText)(pasteModel),
9064
+ textContent: (0, roosterjs_content_model_dom_1.contentModelToText)(textModel),
9062
9065
  };
9063
9066
  }
9064
9067
  }
@@ -9318,6 +9321,7 @@ function generatePasteOptionFromPlugins(editor, clipboardData, fragment, htmlFro
9318
9321
  pasteType: pasteType,
9319
9322
  domToModelOption: domToModelOption,
9320
9323
  containsBlockElements: !!htmlFromClipboard.containsBlockElements,
9324
+ globalCssRules: htmlFromClipboard.globalCssRules,
9321
9325
  };
9322
9326
  return editor.triggerEvent('beforePaste', event, true /* broadcast */);
9323
9327
  }
@@ -9925,6 +9929,7 @@ var announce = function (core, announceData) {
9925
9929
  var textToAnnounce = formatString(template || text, formatStrings);
9926
9930
  if (!core.lifecycle.announceContainer) {
9927
9931
  core.lifecycle.announceContainer = (0, createAriaLiveElement_1.createAriaLiveElement)(core.physicalRoot.ownerDocument);
9932
+ core.domHelper.appendToRoot(core.lifecycle.announceContainer);
9928
9933
  }
9929
9934
  if (textToAnnounce && core.lifecycle.announceContainer) {
9930
9935
  var announceContainer = core.lifecycle.announceContainer;
@@ -10416,16 +10421,19 @@ var getDOMSelection = function (core) {
10416
10421
  exports.getDOMSelection = getDOMSelection;
10417
10422
  function getNewSelection(core) {
10418
10423
  var _a;
10424
+ var range = core.domHelper.getSelectionRange();
10425
+ if (!range || !core.logicalRoot.contains(range.commonAncestorContainer)) {
10426
+ return null;
10427
+ }
10419
10428
  var selection = (_a = core.logicalRoot.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
10420
- var range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
10421
- return selection && range && core.logicalRoot.contains(range.commonAncestorContainer)
10422
- ? {
10423
- type: 'range',
10424
- range: range,
10425
- isReverted: selection.focusNode != range.endContainer ||
10426
- selection.focusOffset != range.endOffset,
10427
- }
10428
- : null;
10429
+ var isReverted = selection
10430
+ ? selection.focusNode != range.endContainer || selection.focusOffset != range.endOffset
10431
+ : false;
10432
+ return {
10433
+ type: 'range',
10434
+ range: range,
10435
+ isReverted: isReverted,
10436
+ };
10429
10437
  }
10430
10438
 
10431
10439
 
@@ -10869,43 +10877,6 @@ var setContentModel = function (core, model, option, onNodeCreated, isInitializi
10869
10877
  exports.setContentModel = setContentModel;
10870
10878
 
10871
10879
 
10872
- /***/ },
10873
-
10874
- /***/ "./packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/addRangeToSelection.ts"
10875
- /*!**************************************************************************************************!*\
10876
- !*** ./packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/addRangeToSelection.ts ***!
10877
- \**************************************************************************************************/
10878
- (__unused_webpack_module, exports, __webpack_require__) {
10879
-
10880
- "use strict";
10881
-
10882
- Object.defineProperty(exports, "__esModule", ({ value: true }));
10883
- exports.addRangeToSelection = void 0;
10884
- var areSameSelections_1 = __webpack_require__(/*! ../../corePlugin/cache/areSameSelections */ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/areSameSelections.ts");
10885
- /**
10886
- * @internal
10887
- */
10888
- function addRangeToSelection(doc, range, isReverted) {
10889
- var _a;
10890
- if (isReverted === void 0) { isReverted = false; }
10891
- var selection = (_a = doc.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
10892
- if (selection) {
10893
- var currentRange = selection.rangeCount > 0 && selection.getRangeAt(0);
10894
- if (currentRange && (0, areSameSelections_1.areSameRanges)(currentRange, range)) {
10895
- return;
10896
- }
10897
- selection.removeAllRanges();
10898
- if (!isReverted) {
10899
- selection.addRange(range);
10900
- }
10901
- else {
10902
- selection.setBaseAndExtent(range.endContainer, range.endOffset, range.startContainer, range.startOffset);
10903
- }
10904
- }
10905
- }
10906
- exports.addRangeToSelection = addRangeToSelection;
10907
-
10908
-
10909
10880
  /***/ },
10910
10881
 
10911
10882
  /***/ "./packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/findLastedCoInMergedCell.ts"
@@ -11007,7 +10978,6 @@ exports.findTableCellElement = findTableCellElement;
11007
10978
 
11008
10979
  Object.defineProperty(exports, "__esModule", ({ value: true }));
11009
10980
  exports.setDOMSelection = void 0;
11010
- var addRangeToSelection_1 = __webpack_require__(/*! ./addRangeToSelection */ "./packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/addRangeToSelection.ts");
11011
10981
  var areSameSelections_1 = __webpack_require__(/*! ../../corePlugin/cache/areSameSelections */ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/areSameSelections.ts");
11012
10982
  var ensureUniqueId_1 = __webpack_require__(/*! ../setEditorStyle/ensureUniqueId */ "./packages/roosterjs-content-model-core/lib/coreApi/setEditorStyle/ensureUniqueId.ts");
11013
10983
  var findLastedCoInMergedCell_1 = __webpack_require__(/*! ./findLastedCoInMergedCell */ "./packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/findLastedCoInMergedCell.ts");
@@ -11033,7 +11003,6 @@ var setDOMSelection = function (core, selection, skipSelectionChangedEvent) {
11033
11003
  // We are applying a new selection, so we don't need to apply cached selection in DOMEventPlugin.
11034
11004
  // Set skipReselectOnFocus to skip this behavior
11035
11005
  var skipReselectOnFocus = core.selection.skipReselectOnFocus;
11036
- var doc = core.physicalRoot.ownerDocument;
11037
11006
  var isDarkMode = core.lifecycle.isDarkMode;
11038
11007
  core.selection.skipReselectOnFocus = true;
11039
11008
  core.api.setEditorStyle(core, DOM_SELECTION_CSS_KEY, null /*cssRule*/);
@@ -11049,7 +11018,7 @@ var setDOMSelection = function (core, selection, skipSelectionChangedEvent) {
11049
11018
  : core.selection.imageSelectionBorderColor;
11050
11019
  core.api.setEditorStyle(core, DOM_SELECTION_CSS_KEY, "outline-style:solid!important; outline-color:" + (imageSelectionColor || DEFAULT_SELECTION_BORDER_COLOR) + "!important;", [(0, roosterjs_content_model_dom_1.getSafeIdSelector)((0, ensureUniqueId_1.ensureUniqueId)(image, IMAGE_ID))]);
11051
11020
  core.api.setEditorStyle(core, HIDE_SELECTION_CSS_KEY, TRANSPARENT_SELECTION_CSS_RULE, [SELECTION_SELECTOR]);
11052
- setRangeSelection(doc, image, false /* collapse */);
11021
+ setRangeSelection(core, image, false /* collapse */);
11053
11022
  break;
11054
11023
  case 'table':
11055
11024
  var table = selection.table, firstColumn = selection.firstColumn, firstRow = selection.firstRow, lastColumn = selection.lastColumn, lastRow = selection.lastRow;
@@ -11086,11 +11055,11 @@ var setDOMSelection = function (core, selection, skipSelectionChangedEvent) {
11086
11055
  (0, toggleCaret_1.toggleCaret)(core, true /* hide */);
11087
11056
  var nodeToSelect = ((_a = firstCell.cell) === null || _a === void 0 ? void 0 : _a.firstElementChild) || firstCell.cell;
11088
11057
  if (nodeToSelect) {
11089
- setRangeSelection(doc, nodeToSelect || undefined, true /* collapse */);
11058
+ setRangeSelection(core, nodeToSelect || undefined, true /* collapse */);
11090
11059
  }
11091
11060
  break;
11092
11061
  case 'range':
11093
- (0, addRangeToSelection_1.addRangeToSelection)(doc, selection.range, selection.isReverted);
11062
+ core.domHelper.setSelectionRange(selection.range, selection.isReverted);
11094
11063
  core.selection.selection = core.domHelper.hasFocus() ? null : selection;
11095
11064
  break;
11096
11065
  default:
@@ -11110,9 +11079,10 @@ var setDOMSelection = function (core, selection, skipSelectionChangedEvent) {
11110
11079
  }
11111
11080
  };
11112
11081
  exports.setDOMSelection = setDOMSelection;
11113
- function setRangeSelection(doc, element, collapse) {
11082
+ function setRangeSelection(core, element, collapse) {
11114
11083
  var _a;
11115
- if (element && doc.contains(element)) {
11084
+ if (element && core.domHelper.isNodeInEditor(element)) {
11085
+ var doc = core.physicalRoot.ownerDocument;
11116
11086
  var range = doc.createRange();
11117
11087
  var isReverted = undefined;
11118
11088
  range.selectNode(element);
@@ -11128,7 +11098,7 @@ function setRangeSelection(doc, element, collapse) {
11128
11098
  selection.focusOffset != range_1.endOffset;
11129
11099
  }
11130
11100
  }
11131
- (0, addRangeToSelection_1.addRangeToSelection)(doc, range, isReverted);
11101
+ core.domHelper.setSelectionRange(range, isReverted);
11132
11102
  }
11133
11103
  }
11134
11104
 
@@ -11315,9 +11285,9 @@ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-mo
11315
11285
  */
11316
11286
  function ensureUniqueId(element, idPrefix) {
11317
11287
  idPrefix = element.id || idPrefix;
11318
- var doc = element.ownerDocument;
11288
+ var root = element.getRootNode();
11319
11289
  var i = 0;
11320
- while (!element.id || doc.querySelectorAll((0, roosterjs_content_model_dom_1.getSafeIdSelector)(element.id)).length > 1) {
11290
+ while (!element.id || root.querySelectorAll((0, roosterjs_content_model_dom_1.getSafeIdSelector)(element.id)).length > 1) {
11321
11291
  element.id = idPrefix + '_' + i++;
11322
11292
  }
11323
11293
  return element.id;
@@ -11350,7 +11320,7 @@ var setEditorStyle = function (core, key, cssRule, subSelectors, maxRuleLength)
11350
11320
  if (!styleElement && cssRule) {
11351
11321
  var doc = core.physicalRoot.ownerDocument;
11352
11322
  styleElement = doc.createElement('style');
11353
- doc.head.appendChild(styleElement);
11323
+ core.domHelper.appendToRoot(styleElement);
11354
11324
  styleElement.dataset.roosterjsStyleKey = key;
11355
11325
  core.lifecycle.styleElements[key] = styleElement;
11356
11326
  }
@@ -11828,12 +11798,13 @@ exports.createParagraphMap = createParagraphMap;
11828
11798
  /*!*****************************************************************************************!*\
11829
11799
  !*** ./packages/roosterjs-content-model-core/lib/corePlugin/cache/areSameSelections.ts ***!
11830
11800
  \*****************************************************************************************/
11831
- (__unused_webpack_module, exports) {
11801
+ (__unused_webpack_module, exports, __webpack_require__) {
11832
11802
 
11833
11803
  "use strict";
11834
11804
 
11835
11805
  Object.defineProperty(exports, "__esModule", ({ value: true }));
11836
- exports.areSameRanges = exports.areSameTableSelections = exports.areSameSelections = void 0;
11806
+ exports.areSameTableSelections = exports.areSameSelections = void 0;
11807
+ var areSameRanges_1 = __webpack_require__(/*! ../../utils/areSameRanges */ "./packages/roosterjs-content-model-core/lib/utils/areSameRanges.ts");
11837
11808
  /**
11838
11809
  * @internal
11839
11810
  * Check if the given selections are the same
@@ -11859,7 +11830,7 @@ function areSameSelections(sel1, sel2) {
11859
11830
  range1.endOffset == end.offset);
11860
11831
  }
11861
11832
  else {
11862
- return areSameRanges(range1, sel2.range);
11833
+ return (0, areSameRanges_1.areSameRanges)(range1, sel2.range);
11863
11834
  }
11864
11835
  }
11865
11836
  else {
@@ -11878,7 +11849,6 @@ var TableSelectionKeys = [
11878
11849
  'firstRow',
11879
11850
  'lastRow',
11880
11851
  ];
11881
- var RangeKeys = ['startContainer', 'endContainer', 'startOffset', 'endOffset'];
11882
11852
  /**
11883
11853
  * @internal
11884
11854
  */
@@ -11886,13 +11856,6 @@ function areSameTableSelections(t1, t2) {
11886
11856
  return areSame(t1, t2, TableSelectionKeys);
11887
11857
  }
11888
11858
  exports.areSameTableSelections = areSameTableSelections;
11889
- /**
11890
- * @internal
11891
- */
11892
- function areSameRanges(r1, r2) {
11893
- return areSame(r1, r2, RangeKeys);
11894
- }
11895
- exports.areSameRanges = areSameRanges;
11896
11859
  function isCacheSelection(sel) {
11897
11860
  return !!sel.start;
11898
11861
  }
@@ -12070,7 +12033,13 @@ var DomIndexerImpl = /** @class */ (function () {
12070
12033
  }
12071
12034
  else {
12072
12035
  var marker1 = this.reconcileNodeSelection(startContainer, startOffset);
12073
- var marker2 = this.reconcileNodeSelection(endContainer, endOffset);
12036
+ // Pass marker1 to the second call so its adjacent-marker cleanup
12037
+ // does not consume the SelectionMarker we just inserted. Without
12038
+ // this guard, when marker1 lands directly next to endContainer's
12039
+ // segment in paragraph.segments (e.g. startOffset == startContainer
12040
+ // text length), the second splice would absorb marker1 and leave
12041
+ // setSelection with a dangling reference. See issue #3341.
12042
+ var marker2 = this.reconcileNodeSelection(endContainer, endOffset, undefined, undefined, marker1);
12074
12043
  if (marker1 && marker2) {
12075
12044
  if (newSelection.isReverted) {
12076
12045
  model.hasRevertedRangeSelection = true;
@@ -12146,10 +12115,10 @@ var DomIndexerImpl = /** @class */ (function () {
12146
12115
  var start = selection.start, end = selection.end;
12147
12116
  return start.node == end.node && start.offset == end.offset;
12148
12117
  };
12149
- DomIndexerImpl.prototype.reconcileNodeSelection = function (node, offset, defaultFormat, selectionMarker) {
12118
+ DomIndexerImpl.prototype.reconcileNodeSelection = function (node, offset, defaultFormat, selectionMarker, preserveMarker) {
12150
12119
  if ((0, roosterjs_content_model_dom_1.isNodeOfType)(node, 'TEXT_NODE')) {
12151
12120
  if (isIndexedSegment(node)) {
12152
- return this.reconcileTextSelection(node, offset, undefined, selectionMarker);
12121
+ return this.reconcileTextSelection(node, offset, undefined, selectionMarker, preserveMarker);
12153
12122
  }
12154
12123
  else if (isIndexedDelimiter(node)) {
12155
12124
  return this.reconcileDelimiterSelection(node, defaultFormat);
@@ -12179,7 +12148,7 @@ var DomIndexerImpl = /** @class */ (function () {
12179
12148
  }
12180
12149
  return marker;
12181
12150
  };
12182
- DomIndexerImpl.prototype.reconcileTextSelection = function (textNode, startOffset, endOffset, selectionMarker) {
12151
+ DomIndexerImpl.prototype.reconcileTextSelection = function (textNode, startOffset, endOffset, selectionMarker, preserveMarker) {
12183
12152
  var _a;
12184
12153
  var _b, _c, _d, _e, _f, _g;
12185
12154
  var _h = textNode.__roosterjsContentModel, paragraph = _h.paragraph, segments = _h.segments;
@@ -12232,11 +12201,13 @@ var DomIndexerImpl = /** @class */ (function () {
12232
12201
  var lastIndex = paragraph.segments.indexOf(last);
12233
12202
  if (firstIndex >= 0 && lastIndex >= 0) {
12234
12203
  while (firstIndex > 0 &&
12235
- paragraph.segments[firstIndex - 1].segmentType == 'SelectionMarker') {
12204
+ paragraph.segments[firstIndex - 1].segmentType == 'SelectionMarker' &&
12205
+ paragraph.segments[firstIndex - 1] !== preserveMarker) {
12236
12206
  firstIndex--;
12237
12207
  }
12238
12208
  while (lastIndex < paragraph.segments.length - 1 &&
12239
- paragraph.segments[lastIndex + 1].segmentType == 'SelectionMarker') {
12209
+ paragraph.segments[lastIndex + 1].segmentType == 'SelectionMarker' &&
12210
+ paragraph.segments[lastIndex + 1] !== preserveMarker) {
12240
12211
  lastIndex++;
12241
12212
  }
12242
12213
  (_a = paragraph.segments).splice.apply(_a, (0, tslib_1.__spreadArray)([firstIndex, lastIndex - firstIndex + 1], (0, tslib_1.__read)(newSegments), false));
@@ -14354,6 +14325,7 @@ var LifecyclePlugin = /** @class */ (function () {
14354
14325
  delete this.state.rewriteFromModel;
14355
14326
  // Initialize the Announce container.
14356
14327
  this.state.announceContainer = (0, createAriaLiveElement_1.createAriaLiveElement)(editor.getDocument());
14328
+ editor.getDOMHelper().appendToRoot(this.state.announceContainer);
14357
14329
  };
14358
14330
  /**
14359
14331
  * Dispose this plugin
@@ -14547,20 +14519,23 @@ var SelectionPlugin = /** @class */ (function () {
14547
14519
  }
14548
14520
  };
14549
14521
  this.onSelectionChange = function () {
14550
- var _a;
14522
+ var _a, _b;
14551
14523
  if (((_a = _this.editor) === null || _a === void 0 ? void 0 : _a.hasFocus()) && !_this.editor.isInShadowEdit()) {
14552
14524
  var newSelection = _this.editor.getDOMSelection();
14525
+ var domHelper = _this.editor.getDOMHelper();
14553
14526
  //If am image selection changed to a wider range due a keyboard event, we should update the selection
14554
- var selection = _this.editor.getDocument().getSelection();
14555
- if (selection && selection.focusNode) {
14556
- var image = (0, isSingleImageInSelection_1.isSingleImageInSelection)(selection);
14527
+ var range = domHelper.getSelectionRange();
14528
+ if (range) {
14529
+ var image = (0, isSingleImageInSelection_1.isSingleImageInSelection)(range);
14557
14530
  if ((newSelection === null || newSelection === void 0 ? void 0 : newSelection.type) == 'image' && !image) {
14558
- var range = selection.getRangeAt(0);
14531
+ var sel = (_b = _this.editor.getDocument().defaultView) === null || _b === void 0 ? void 0 : _b.getSelection();
14532
+ var isReverted = sel
14533
+ ? sel.focusNode != range.endContainer || sel.focusOffset != range.endOffset
14534
+ : false;
14559
14535
  _this.editor.setDOMSelection({
14560
14536
  type: 'range',
14561
14537
  range: range,
14562
- isReverted: selection.focusNode != range.endContainer ||
14563
- selection.focusOffset != range.endOffset,
14538
+ isReverted: isReverted,
14564
14539
  });
14565
14540
  }
14566
14541
  else if ((newSelection === null || newSelection === void 0 ? void 0 : newSelection.type) !== 'image' && image) {
@@ -15949,10 +15924,23 @@ exports.Editor = Editor;
15949
15924
 
15950
15925
  Object.defineProperty(exports, "__esModule", ({ value: true }));
15951
15926
  exports.createDOMHelper = void 0;
15927
+ var areSameRanges_1 = __webpack_require__(/*! ../../utils/areSameRanges */ "./packages/roosterjs-content-model-core/lib/utils/areSameRanges.ts");
15952
15928
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
15929
+ function isSelectionWithComposedRanges(sel) {
15930
+ return 'getComposedRanges' in sel;
15931
+ }
15932
+ function isShadowRoot(node) {
15933
+ return 'host' in node;
15934
+ }
15953
15935
  var DOMHelperImpl = /** @class */ (function () {
15954
15936
  function DOMHelperImpl(contentDiv, options) {
15937
+ var _a;
15955
15938
  this.contentDiv = contentDiv;
15939
+ var rootNode = contentDiv.getRootNode();
15940
+ this.shadowRoot = (options === null || options === void 0 ? void 0 : options.useShadowDom) && isShadowRoot(rootNode) ? rootNode : null;
15941
+ this.doc = contentDiv.ownerDocument;
15942
+ var sel = (_a = this.doc.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
15943
+ this.useComposedRanges = !!(this.shadowRoot && sel && 'getComposedRanges' in sel);
15956
15944
  }
15957
15945
  DOMHelperImpl.prototype.queryElements = function (selector) {
15958
15946
  return (0, roosterjs_content_model_dom_1.toArray)(this.contentDiv.querySelectorAll(selector));
@@ -16014,7 +16002,9 @@ var DOMHelperImpl = /** @class */ (function () {
16014
16002
  return this.contentDiv;
16015
16003
  };
16016
16004
  DOMHelperImpl.prototype.hasFocus = function () {
16017
- var activeElement = this.contentDiv.ownerDocument.activeElement;
16005
+ var activeElement = this.shadowRoot
16006
+ ? this.shadowRoot.activeElement
16007
+ : this.doc.activeElement;
16018
16008
  return !!(activeElement && this.contentDiv.contains(activeElement));
16019
16009
  };
16020
16010
  /**
@@ -16081,6 +16071,51 @@ var DOMHelperImpl = /** @class */ (function () {
16081
16071
  DOMHelperImpl.prototype.getRangesByText = function (text, matchCase, wholeWord) {
16082
16072
  return (0, roosterjs_content_model_dom_1.getRangesByText)(this.contentDiv, text, matchCase, wholeWord, true /*editableOnly*/);
16083
16073
  };
16074
+ DOMHelperImpl.prototype.getSelectionRange = function () {
16075
+ var _a;
16076
+ var sel = (_a = this.doc.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
16077
+ if (!sel) {
16078
+ return null;
16079
+ }
16080
+ if (this.useComposedRanges && this.shadowRoot && isSelectionWithComposedRanges(sel)) {
16081
+ var staticRanges = sel.getComposedRanges({
16082
+ shadowRoots: [this.shadowRoot],
16083
+ });
16084
+ if ((staticRanges === null || staticRanges === void 0 ? void 0 : staticRanges.length) > 0) {
16085
+ var sr = staticRanges[0];
16086
+ var range = this.doc.createRange();
16087
+ range.setStart(sr.startContainer, sr.startOffset);
16088
+ range.setEnd(sr.endContainer, sr.endOffset);
16089
+ return range;
16090
+ }
16091
+ return null;
16092
+ }
16093
+ return sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
16094
+ };
16095
+ DOMHelperImpl.prototype.setSelectionRange = function (range, isReverted) {
16096
+ var _a;
16097
+ if (isReverted === void 0) { isReverted = false; }
16098
+ var sel = (_a = this.doc.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
16099
+ var currentRange = this.getSelectionRange();
16100
+ if (!sel || (currentRange && (0, areSameRanges_1.areSameRanges)(range, currentRange))) {
16101
+ return;
16102
+ }
16103
+ var startContainer = range.startContainer, startOffset = range.startOffset, endContainer = range.endContainer, endOffset = range.endOffset;
16104
+ if (!isReverted) {
16105
+ sel.setBaseAndExtent(startContainer, startOffset, endContainer, endOffset);
16106
+ }
16107
+ else {
16108
+ sel.setBaseAndExtent(endContainer, endOffset, startContainer, startOffset);
16109
+ }
16110
+ };
16111
+ DOMHelperImpl.prototype.appendToRoot = function (element) {
16112
+ if (this.shadowRoot) {
16113
+ this.shadowRoot.appendChild(element);
16114
+ }
16115
+ else {
16116
+ this.doc.body.appendChild(element);
16117
+ }
16118
+ };
16084
16119
  return DOMHelperImpl;
16085
16120
  }());
16086
16121
  /**
@@ -16197,7 +16232,10 @@ function createEditorCore(contentDiv, options) {
16197
16232
  corePlugins.lifecycle,
16198
16233
  ], false), environment: createEditorEnvironment(contentDiv, options), darkColorHandler: (0, DarkColorHandlerImpl_1.createDarkColorHandler)(contentDiv, (_b = options.getDarkColor) !== null && _b !== void 0 ? _b : getDarkColorFallback, options.knownColors, options.generateColorKey), trustedHTMLHandler: options.trustedHTMLHandler && !(0, domCreator_1.isDOMCreator)(options.trustedHTMLHandler)
16199
16234
  ? options.trustedHTMLHandler
16200
- : (0, domCreator_1.createTrustedHTMLHandler)(domCreator), domCreator: domCreator, domHelper: (0, DOMHelperImpl_1.createDOMHelper)(contentDiv) }, getPluginState(corePlugins)), { disposeErrorHandler: options.disposeErrorHandler, onFixUpModel: options.onFixUpModel, experimentalFeatures: options.experimentalFeatures ? (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(options.experimentalFeatures), false) : [] });
16235
+ : (0, domCreator_1.createTrustedHTMLHandler)(domCreator), domCreator: domCreator, domHelper: (0, DOMHelperImpl_1.createDOMHelper)(contentDiv, {
16236
+ useShadowDom: !!options.experimentalFeatures &&
16237
+ options.experimentalFeatures.indexOf('ShadowDom') >= 0,
16238
+ }) }, getPluginState(corePlugins)), { disposeErrorHandler: options.disposeErrorHandler, onFixUpModel: options.onFixUpModel, experimentalFeatures: options.experimentalFeatures ? (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(options.experimentalFeatures), false) : [] });
16201
16239
  }
16202
16240
  exports.createEditorCore = createEditorCore;
16203
16241
  function createEditorEnvironment(contentDiv, options) {
@@ -16355,6 +16393,8 @@ var containerSizeFormatParser = function (format, element) {
16355
16393
  if (element.tagName == 'DIV' || element.tagName == 'P') {
16356
16394
  delete format.width;
16357
16395
  delete format.height;
16396
+ delete format.maxHeight;
16397
+ delete format.maxWidth;
16358
16398
  }
16359
16399
  };
16360
16400
  exports.containerSizeFormatParser = containerSizeFormatParser;
@@ -16651,6 +16691,29 @@ var pasteWhiteSpaceFormatParser = function (format, element, context, defaultSty
16651
16691
  exports.pasteWhiteSpaceFormatParser = pasteWhiteSpaceFormatParser;
16652
16692
 
16653
16693
 
16694
+ /***/ },
16695
+
16696
+ /***/ "./packages/roosterjs-content-model-core/lib/utils/areSameRanges.ts"
16697
+ /*!**************************************************************************!*\
16698
+ !*** ./packages/roosterjs-content-model-core/lib/utils/areSameRanges.ts ***!
16699
+ \**************************************************************************/
16700
+ (__unused_webpack_module, exports) {
16701
+
16702
+ "use strict";
16703
+
16704
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
16705
+ exports.areSameRanges = void 0;
16706
+ var RangeKeys = ['startContainer', 'endContainer', 'startOffset', 'endOffset'];
16707
+ /**
16708
+ * @internal
16709
+ * Check if two ranges have the same start and end positions.
16710
+ */
16711
+ function areSameRanges(r1, r2) {
16712
+ return RangeKeys.every(function (k) { return r1[k] == r2[k]; });
16713
+ }
16714
+ exports.areSameRanges = areSameRanges;
16715
+
16716
+
16654
16717
  /***/ },
16655
16718
 
16656
16719
  /***/ "./packages/roosterjs-content-model-core/lib/utils/createAriaLiveElement.ts"
@@ -16676,7 +16739,6 @@ function createAriaLiveElement(document) {
16676
16739
  div.style.whiteSpace = 'nowrap';
16677
16740
  div.style.width = '1px';
16678
16741
  div.ariaLive = 'assertive';
16679
- document.body.appendChild(div);
16680
16742
  return div;
16681
16743
  }
16682
16744
  exports.createAriaLiveElement = createAriaLiveElement;
@@ -21167,11 +21229,13 @@ exports.directionFormatHandler = {
21167
21229
  format.direction = dir == 'rtl' ? 'rtl' : 'ltr';
21168
21230
  }
21169
21231
  },
21170
- apply: function (format, element) {
21232
+ apply: function (format, element, context) {
21171
21233
  if (format.direction) {
21172
21234
  element.style.direction = format.direction;
21173
21235
  }
21174
- if (format.direction == 'rtl' && (0, isElementOfType_1.isElementOfType)(element, 'table')) {
21236
+ if (format.direction == 'rtl' &&
21237
+ (0, isElementOfType_1.isElementOfType)(element, 'table') &&
21238
+ context.implicitFormat.direction != 'rtl') {
21175
21239
  element.style.justifySelf = 'flex-end';
21176
21240
  }
21177
21241
  },
@@ -21708,6 +21772,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
21708
21772
  exports.borderFormatHandler = void 0;
21709
21773
  var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
21710
21774
  var borderKeys_1 = __webpack_require__(/*! ../utils/borderKeys */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/utils/borderKeys.ts");
21775
+ var borderValues_1 = __webpack_require__(/*! ../../domUtils/style/borderValues */ "./packages/roosterjs-content-model-dom/lib/domUtils/style/borderValues.ts");
21711
21776
  // This array needs to match BorderKeys array
21712
21777
  var BorderWidthKeys = [
21713
21778
  'borderTopWidth',
@@ -21736,7 +21801,17 @@ exports.borderFormatHandler = {
21736
21801
  width = '0px';
21737
21802
  }
21738
21803
  if (value && width != defaultWidth) {
21739
- format[key] = value == 'none' ? '' : value;
21804
+ var result = value;
21805
+ if (result.includes('initial')) {
21806
+ // Remove 'initial' from the last part (color) of the border value
21807
+ // since browsers ignore it when setting the inline style property
21808
+ var border = (0, borderValues_1.extractBorderValues)(value);
21809
+ if (border.color === 'initial') {
21810
+ border.color = '';
21811
+ }
21812
+ result = (0, borderValues_1.combineBorderValue)(border);
21813
+ }
21814
+ format[key] = result == 'none' ? '' : result;
21740
21815
  }
21741
21816
  });
21742
21817
  var borderRadius = element.style.borderRadius;
@@ -24138,6 +24213,7 @@ var createText_1 = __webpack_require__(/*! ../creators/createText */ "./packages
24138
24213
  var ensureParagraph_1 = __webpack_require__(/*! ./ensureParagraph */ "./packages/roosterjs-content-model-dom/lib/modelApi/common/ensureParagraph.ts");
24139
24214
  var hasSpacesOnly_1 = __webpack_require__(/*! ./hasSpacesOnly */ "./packages/roosterjs-content-model-dom/lib/modelApi/common/hasSpacesOnly.ts");
24140
24215
  var isWhiteSpacePreserved_1 = __webpack_require__(/*! ../../domUtils/isWhiteSpacePreserved */ "./packages/roosterjs-content-model-dom/lib/domUtils/isWhiteSpacePreserved.ts");
24216
+ var stripInvisibleUnicode_1 = __webpack_require__(/*! ./stripInvisibleUnicode */ "./packages/roosterjs-content-model-dom/lib/modelApi/common/stripInvisibleUnicode.ts");
24141
24217
  /**
24142
24218
  * Add a new text segment to current paragraph
24143
24219
  * @param group Current BlockGroup that the paragraph belong to
@@ -24153,7 +24229,11 @@ function addTextSegment(group, text, context) {
24153
24229
  if (!(0, hasSpacesOnly_1.hasSpacesOnly)(text) ||
24154
24230
  ((_a = paragraph === null || paragraph === void 0 ? void 0 : paragraph.segments.length) !== null && _a !== void 0 ? _a : 0) > 0 ||
24155
24231
  (0, isWhiteSpacePreserved_1.isWhiteSpacePreserved)(paragraph === null || paragraph === void 0 ? void 0 : paragraph.format.whiteSpace)) {
24156
- textModel = (0, createText_1.createText)(text, context.segmentFormat);
24232
+ var filteredText = context.experimentalFeatures &&
24233
+ context.experimentalFeatures.indexOf('FilterInvisibleUnicode') > -1
24234
+ ? (0, stripInvisibleUnicode_1.stripInvisibleUnicode)(text)
24235
+ : text;
24236
+ textModel = (0, createText_1.createText)(filteredText, context.segmentFormat);
24157
24237
  if (context.isInSelection) {
24158
24238
  textModel.isSelected = true;
24159
24239
  }
@@ -24788,6 +24868,34 @@ function normalizeSegmentFormat(format, environment) {
24788
24868
  exports.normalizeSegmentFormat = normalizeSegmentFormat;
24789
24869
 
24790
24870
 
24871
+ /***/ },
24872
+
24873
+ /***/ "./packages/roosterjs-content-model-dom/lib/modelApi/common/stripInvisibleUnicode.ts"
24874
+ /*!*******************************************************************************************!*\
24875
+ !*** ./packages/roosterjs-content-model-dom/lib/modelApi/common/stripInvisibleUnicode.ts ***!
24876
+ \*******************************************************************************************/
24877
+ (__unused_webpack_module, exports) {
24878
+
24879
+ "use strict";
24880
+
24881
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
24882
+ exports.stripInvisibleUnicode = void 0;
24883
+ // According to https://embracethered.com/blog/posts/2024/hiding-and-finding-text-with-unicode-tags/
24884
+ // there are some invisible unicode characters in the range of U+E0000 to U+EFFFF, which are used for hiding text in HTML.
24885
+ // We need to strip them out before processing the pasted content, otherwise they will be treated as normal text and cause unexpected behavior.
24886
+ var INVISIBLE_UNICODE_REGEX = /[\u{E0000}-\u{EFFFF}]/gu;
24887
+ /**
24888
+ * @internal
24889
+ * Strip invisible unicode characters from the given string
24890
+ * @param value The string to be processed
24891
+ * @returns The string with invisible unicode characters removed
24892
+ */
24893
+ function stripInvisibleUnicode(value) {
24894
+ return value.replace(INVISIBLE_UNICODE_REGEX, '');
24895
+ }
24896
+ exports.stripInvisibleUnicode = stripInvisibleUnicode;
24897
+
24898
+
24791
24899
  /***/ },
24792
24900
 
24793
24901
  /***/ "./packages/roosterjs-content-model-dom/lib/modelApi/common/unwrapBlock.ts"
@@ -25246,16 +25354,25 @@ exports.createParagraphDecorator = createParagraphDecorator;
25246
25354
 
25247
25355
  Object.defineProperty(exports, "__esModule", ({ value: true }));
25248
25356
  exports.createSelectionMarker = void 0;
25249
- var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
25357
+ var EmptySegmentFormat_1 = __webpack_require__(/*! ../../constants/EmptySegmentFormat */ "./packages/roosterjs-content-model-dom/lib/constants/EmptySegmentFormat.ts");
25358
+ var getObjectKeys_1 = __webpack_require__(/*! ../../domUtils/getObjectKeys */ "./packages/roosterjs-content-model-dom/lib/domUtils/getObjectKeys.ts");
25250
25359
  /**
25251
25360
  * Create a ContentModelSelectionMarker model
25252
25361
  * @param format @optional The format of this model
25253
25362
  */
25254
25363
  function createSelectionMarker(format) {
25364
+ var filteredFormat = {};
25365
+ if (format) {
25366
+ (0, getObjectKeys_1.getObjectKeys)(EmptySegmentFormat_1.EmptySegmentFormat).forEach(function (key) {
25367
+ if (key in format) {
25368
+ filteredFormat[key] = format[key];
25369
+ }
25370
+ });
25371
+ }
25255
25372
  return {
25256
25373
  segmentType: 'SelectionMarker',
25257
25374
  isSelected: true,
25258
- format: (0, tslib_1.__assign)({}, format),
25375
+ format: filteredFormat,
25259
25376
  };
25260
25377
  }
25261
25378
  exports.createSelectionMarker = createSelectionMarker;
@@ -29330,14 +29447,16 @@ var handleFormatContainer = function (doc, parent, container, context, refNode)
29330
29447
  (0, applyFormat_1.applyFormat)(containerNode_1, context.formatAppliers.segmentOnBlock, container.format, context);
29331
29448
  (0, applyFormat_1.applyFormat)(containerNode_1, context.formatAppliers.container, container.format, context);
29332
29449
  });
29333
- if (container.tagName == 'pre') {
29334
- (0, stackFormat_1.stackFormat)(context, PreChildFormat, function () {
29450
+ (0, stackFormat_1.stackFormat)(context, container.format.direction ? { direction: container.format.direction } : null, function () {
29451
+ if (container.tagName == 'pre') {
29452
+ (0, stackFormat_1.stackFormat)(context, PreChildFormat, function () {
29453
+ context.modelHandlers.blockGroupChildren(doc, containerNode_1, container, context);
29454
+ });
29455
+ }
29456
+ else {
29335
29457
  context.modelHandlers.blockGroupChildren(doc, containerNode_1, container, context);
29336
- });
29337
- }
29338
- else {
29339
- context.modelHandlers.blockGroupChildren(doc, containerNode_1, container, context);
29340
- }
29458
+ }
29459
+ });
29341
29460
  element = containerNode_1;
29342
29461
  }
29343
29462
  if (element) {
@@ -29627,7 +29746,9 @@ var handleListItem = function (doc, parent, listItem, context, refNode) {
29627
29746
  // Need to apply listItemElement formats after applying metadata since the list numbers value relies on the result of metadata handling
29628
29747
  (0, applyFormat_1.applyFormat)(li, context.formatAppliers.listItemElement, listItem.format, context);
29629
29748
  (0, stackFormat_1.stackFormat)(context, listItem.formatHolder.format, function () {
29630
- context.modelHandlers.blockGroupChildren(doc, li, listItem, context);
29749
+ (0, stackFormat_1.stackFormat)(context, listItem.format.direction ? { direction: listItem.format.direction } : null, function () {
29750
+ context.modelHandlers.blockGroupChildren(doc, li, listItem, context);
29751
+ });
29631
29752
  });
29632
29753
  }
29633
29754
  else {
@@ -29999,7 +30120,9 @@ var handleTable = function (doc, parent, table, context, refNode) {
29999
30120
  (0, applyFormat_1.applyFormat)(td_1, context.formatAppliers.tableCellBorder, cell.format, context);
30000
30121
  (0, applyFormat_1.applyFormat)(td_1, context.formatAppliers.dataset, cell.dataset, context);
30001
30122
  }
30002
- context.modelHandlers.blockGroupChildren(doc, td_1, cell, context);
30123
+ (0, stackFormat_1.stackFormat)(context, cell.format.direction ? { direction: cell.format.direction } : null, function () {
30124
+ context.modelHandlers.blockGroupChildren(doc, td_1, cell, context);
30125
+ });
30003
30126
  });
30004
30127
  (_f = context.onNodeCreated) === null || _f === void 0 ? void 0 : _f.call(context, cell, td_1);
30005
30128
  }
@@ -30525,35 +30648,6 @@ var convertContentModelToMarkdown_1 = __webpack_require__(/*! ./modelToMarkdown/
30525
30648
  Object.defineProperty(exports, "convertContentModelToMarkdown", ({ enumerable: true, get: function () { return convertContentModelToMarkdown_1.convertContentModelToMarkdown; } }));
30526
30649
 
30527
30650
 
30528
- /***/ },
30529
-
30530
- /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applyLink.ts"
30531
- /*!*********************************************************************************************!*\
30532
- !*** ./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applyLink.ts ***!
30533
- \*********************************************************************************************/
30534
- (__unused_webpack_module, exports) {
30535
-
30536
- "use strict";
30537
-
30538
- Object.defineProperty(exports, "__esModule", ({ value: true }));
30539
- exports.applyLink = void 0;
30540
- /**
30541
- * @internal
30542
- */
30543
- function applyLink(textSegment, text, url) {
30544
- textSegment.text = text;
30545
- textSegment.link = {
30546
- dataset: {},
30547
- format: {
30548
- href: url,
30549
- underline: true,
30550
- },
30551
- };
30552
- return textSegment;
30553
- }
30554
- exports.applyLink = applyLink;
30555
-
30556
-
30557
30651
  /***/ },
30558
30652
 
30559
30653
  /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applySegmentFormatting.ts"
@@ -30568,46 +30662,39 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
30568
30662
  exports.applySegmentFormatting = void 0;
30569
30663
  var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
30570
30664
  var adjustHeading_1 = __webpack_require__(/*! ../utils/adjustHeading */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/adjustHeading.ts");
30571
- var applyLink_1 = __webpack_require__(/*! ./applyLink */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applyLink.ts");
30572
- var applyTextFormatting_1 = __webpack_require__(/*! ./applyTextFormatting */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applyTextFormatting.ts");
30573
30665
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
30574
- var createImageSegment_1 = __webpack_require__(/*! ../creators/createImageSegment */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/creators/createImageSegment.ts");
30575
- var splitParagraphSegments_1 = __webpack_require__(/*! ../utils/splitParagraphSegments */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/splitParagraphSegments.ts");
30666
+ var parseInlineSegments_1 = __webpack_require__(/*! ../utils/parseInlineSegments */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/parseInlineSegments.ts");
30576
30667
  /**
30577
30668
  * @internal
30578
30669
  */
30579
30670
  function applySegmentFormatting(text, paragraph, decorator) {
30580
- var e_1, _a, _b;
30671
+ var e_1, _a;
30581
30672
  if (text.length === 0) {
30582
30673
  var br = (0, roosterjs_content_model_dom_1.createBr)();
30583
30674
  paragraph.segments.push(br);
30584
30675
  }
30585
30676
  else {
30586
- var textSegments = (0, splitParagraphSegments_1.splitParagraphSegments)(text);
30677
+ var segments = [];
30678
+ (0, parseInlineSegments_1.parseInlineSegments)(text, segments);
30679
+ // Apply heading adjustment to the first text-bearing segment, if any.
30680
+ var headingAdjusted = false;
30587
30681
  try {
30588
- for (var textSegments_1 = (0, tslib_1.__values)(textSegments), textSegments_1_1 = textSegments_1.next(); !textSegments_1_1.done; textSegments_1_1 = textSegments_1.next()) {
30589
- var segment = textSegments_1_1.value;
30590
- var formattedSegment = (0, roosterjs_content_model_dom_1.createText)(segment.text);
30591
- if (segment.type === 'image') {
30592
- var image = (0, createImageSegment_1.createImageSegment)(segment.text, segment.url);
30593
- paragraph.segments.push(image);
30594
- }
30595
- else {
30596
- if (segment.type === 'link') {
30597
- (0, applyLink_1.applyLink)(formattedSegment, segment.text, segment.url);
30598
- }
30599
- var segmentWithAdjustedHeading = (0, adjustHeading_1.adjustHeading)(formattedSegment, decorator);
30600
- if (segmentWithAdjustedHeading) {
30601
- var formattedSegments = (0, applyTextFormatting_1.applyTextFormatting)(formattedSegment);
30602
- (_b = paragraph.segments).push.apply(_b, (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(formattedSegments), false));
30682
+ for (var segments_1 = (0, tslib_1.__values)(segments), segments_1_1 = segments_1.next(); !segments_1_1.done; segments_1_1 = segments_1.next()) {
30683
+ var segment = segments_1_1.value;
30684
+ if (!headingAdjusted && segment.segmentType === 'Text') {
30685
+ var adjusted = (0, adjustHeading_1.adjustHeading)(segment, decorator);
30686
+ headingAdjusted = true;
30687
+ if (!adjusted) {
30688
+ continue;
30603
30689
  }
30604
30690
  }
30691
+ paragraph.segments.push(segment);
30605
30692
  }
30606
30693
  }
30607
30694
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
30608
30695
  finally {
30609
30696
  try {
30610
- if (textSegments_1_1 && !textSegments_1_1.done && (_a = textSegments_1.return)) _a.call(textSegments_1);
30697
+ if (segments_1_1 && !segments_1_1.done && (_a = segments_1.return)) _a.call(segments_1);
30611
30698
  }
30612
30699
  finally { if (e_1) throw e_1.error; }
30613
30700
  }
@@ -30617,148 +30704,6 @@ function applySegmentFormatting(text, paragraph, decorator) {
30617
30704
  exports.applySegmentFormatting = applySegmentFormatting;
30618
30705
 
30619
30706
 
30620
- /***/ },
30621
-
30622
- /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applyTextFormatting.ts"
30623
- /*!*******************************************************************************************************!*\
30624
- !*** ./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applyTextFormatting.ts ***!
30625
- \*******************************************************************************************************/
30626
- (__unused_webpack_module, exports, __webpack_require__) {
30627
-
30628
- "use strict";
30629
-
30630
- Object.defineProperty(exports, "__esModule", ({ value: true }));
30631
- exports.applyTextFormatting = void 0;
30632
- var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
30633
- var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
30634
- /**
30635
- * @internal
30636
- */
30637
- function applyTextFormatting(textSegment) {
30638
- var text = textSegment.text;
30639
- // Quick check: if the text contains only formatting markers, return original
30640
- if (isOnlyFormattingMarkers(text)) {
30641
- return [textSegment];
30642
- }
30643
- var textSegments = [];
30644
- var currentState = { bold: false, italic: false, strikethrough: false };
30645
- var currentText = '';
30646
- var i = 0;
30647
- while (i < text.length) {
30648
- var marker = parseMarkerAt(text, i);
30649
- if (marker) {
30650
- // Check if this marker should be treated as formatting or as literal text
30651
- if (shouldToggleFormatting(text, i, marker, currentState)) {
30652
- // If we have accumulated text, create a segment for it
30653
- if (currentText.length > 0) {
30654
- textSegments.push(createFormattedSegment(currentText, textSegment.format, currentState, textSegment.link));
30655
- currentText = '';
30656
- }
30657
- // Toggle the formatting state
30658
- toggleFormatting(currentState, marker.type);
30659
- // Skip the marker characters
30660
- i += marker.length;
30661
- }
30662
- else {
30663
- // Treat as regular text if marker is not valid in this context
30664
- currentText += text[i];
30665
- i++;
30666
- }
30667
- }
30668
- else {
30669
- // Regular character, add to current text
30670
- currentText += text[i];
30671
- i++;
30672
- }
30673
- }
30674
- // Add any remaining text as a final segment
30675
- if (currentText.length > 0) {
30676
- textSegments.push(createFormattedSegment(currentText, textSegment.format, currentState, textSegment.link));
30677
- }
30678
- // If no meaningful formatting was applied, return the original segment
30679
- if (textSegments.length === 0 ||
30680
- (textSegments.length === 1 && textSegments[0].text === textSegment.text)) {
30681
- return [textSegment];
30682
- }
30683
- return textSegments;
30684
- }
30685
- exports.applyTextFormatting = applyTextFormatting;
30686
- function isOnlyFormattingMarkers(text) {
30687
- // Remove all potential formatting markers and see if anything remains
30688
- var remaining = text;
30689
- remaining = remaining.replace(/\*\*/g, ''); // Remove **
30690
- remaining = remaining.replace(/~~/g, ''); // Remove ~~
30691
- remaining = remaining.replace(/\*/g, ''); // Remove *
30692
- // If nothing remains after removing all markers, it was only markers
30693
- return remaining.length === 0;
30694
- }
30695
- function parseMarkerAt(text, index) {
30696
- var remaining = text.substring(index);
30697
- if (remaining.startsWith('~~')) {
30698
- return { type: 'strikethrough', length: 2 };
30699
- }
30700
- if (remaining.startsWith('**')) {
30701
- return { type: 'bold', length: 2 };
30702
- }
30703
- if (remaining.startsWith('*')) {
30704
- return { type: 'italic', length: 1 };
30705
- }
30706
- return null;
30707
- }
30708
- function shouldToggleFormatting(text, index, marker, currentState) {
30709
- var nextChar = index + marker.length < text.length ? text.charAt(index + marker.length) : '';
30710
- var isCurrentlyActive = getCurrentFormatState(currentState, marker.type);
30711
- if (isCurrentlyActive) {
30712
- // We're currently in this format, so any marker can close it
30713
- return true;
30714
- }
30715
- else {
30716
- // We're not in this format, so this marker would open it
30717
- // Opening markers must be followed by non-whitespace
30718
- return nextChar.length > 0 && !isWhitespace(nextChar);
30719
- }
30720
- }
30721
- function isWhitespace(char) {
30722
- return /\s/.test(char);
30723
- }
30724
- function toggleFormatting(state, type) {
30725
- switch (type) {
30726
- case 'bold':
30727
- state.bold = !state.bold;
30728
- break;
30729
- case 'italic':
30730
- state.italic = !state.italic;
30731
- break;
30732
- case 'strikethrough':
30733
- state.strikethrough = !state.strikethrough;
30734
- break;
30735
- }
30736
- }
30737
- function getCurrentFormatState(state, type) {
30738
- switch (type) {
30739
- case 'bold':
30740
- return state.bold;
30741
- case 'italic':
30742
- return state.italic;
30743
- case 'strikethrough':
30744
- return state.strikethrough;
30745
- }
30746
- }
30747
- function createFormattedSegment(text, baseFormat, state, link) {
30748
- var format = (0, tslib_1.__assign)({}, baseFormat);
30749
- if (state.bold) {
30750
- format.fontWeight = 'bold';
30751
- }
30752
- if (state.italic) {
30753
- format.italic = true;
30754
- }
30755
- if (state.strikethrough) {
30756
- format.strikethrough = true;
30757
- }
30758
- return (0, roosterjs_content_model_dom_1.createText)(text, format, link);
30759
- }
30760
-
30761
-
30762
30707
  /***/ },
30763
30708
 
30764
30709
  /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/convertMarkdownToContentModel.ts"
@@ -31356,29 +31301,143 @@ exports.isMarkdownTable = isMarkdownTable;
31356
31301
 
31357
31302
  /***/ },
31358
31303
 
31359
- /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/splitParagraphSegments.ts"
31360
- /*!*******************************************************************************************************!*\
31361
- !*** ./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/splitParagraphSegments.ts ***!
31362
- \*******************************************************************************************************/
31363
- (__unused_webpack_module, exports) {
31304
+ /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/parseInlineSegments.ts"
31305
+ /*!****************************************************************************************************!*\
31306
+ !*** ./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/parseInlineSegments.ts ***!
31307
+ \****************************************************************************************************/
31308
+ (__unused_webpack_module, exports, __webpack_require__) {
31364
31309
 
31365
31310
  "use strict";
31366
31311
 
31367
31312
  Object.defineProperty(exports, "__esModule", ({ value: true }));
31368
- exports.splitParagraphSegments = void 0;
31369
- // Matches markdown links and images in a string.
31370
- // Group 1 (full link): [text](url) e.g. [Click here](https://example.com)
31371
- // Group 2: link text e.g. "Click here"
31372
- // Group 3: link url e.g. "https://example.com"
31373
- // Group 4 (full image): ![alt](url) e.g. ![Logo](https://example.com/logo.png)
31374
- // Group 5: alt text e.g. "Logo"
31375
- // Group 6: image url e.g. "https://example.com/logo.png"
31376
- var linkRegex = /(\[([^\[]+)\]\(([^\)]+)\))|(\!\[([^\[]+)\]\(([^\)]+)\))/g;
31377
- var isValidUrl = function (url) {
31313
+ exports.parseInlineSegments = void 0;
31314
+ var createImageSegment_1 = __webpack_require__(/*! ../creators/createImageSegment */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/creators/createImageSegment.ts");
31315
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
31316
+ // Matches a markdown link [text](url) anchored at the start of the input.
31317
+ var linkPattern = /^\[([^\[\]]+)\]\(([^\)]+)\)/;
31318
+ // Matches a markdown image ![alt](url) anchored at the start of the input.
31319
+ var imagePattern = /^!\[([^\[\]]+)\]\(([^\)]+)\)/;
31320
+ /**
31321
+ * @internal
31322
+ * Parse a markdown inline string into Content Model segments. Supports bold/italic/
31323
+ * strikethrough markers, links, and images, and keeps formatting state active across
31324
+ * link boundaries (e.g. **[link](url)**).
31325
+ */
31326
+ function parseInlineSegments(text, segments, state, link) {
31327
+ if (state === void 0) { state = { bold: false, italic: false, strikethrough: false }; }
31328
+ var buffer = '';
31329
+ var i = 0;
31330
+ var flushBuffer = function () {
31331
+ if (buffer.length > 0) {
31332
+ segments.push(createFormattedSegment(buffer, state, link));
31333
+ buffer = '';
31334
+ }
31335
+ };
31336
+ while (i < text.length) {
31337
+ var remaining = text.substring(i);
31338
+ // Image: ![alt](url)
31339
+ var imgMatch = imagePattern.exec(remaining);
31340
+ if (imgMatch && isValidUrl(imgMatch[2])) {
31341
+ flushBuffer();
31342
+ segments.push((0, createImageSegment_1.createImageSegment)(imgMatch[1], imgMatch[2]));
31343
+ i += imgMatch[0].length;
31344
+ continue;
31345
+ }
31346
+ // Link: [text](url) — keep outer formatting state active inside the link
31347
+ var linkMatch = linkPattern.exec(remaining);
31348
+ if (linkMatch && isValidUrl(linkMatch[2])) {
31349
+ flushBuffer();
31350
+ var innerLink = {
31351
+ dataset: {},
31352
+ format: { href: linkMatch[2], underline: true },
31353
+ };
31354
+ parseInlineSegments(linkMatch[1], segments, state, innerLink);
31355
+ i += linkMatch[0].length;
31356
+ continue;
31357
+ }
31358
+ // Formatting marker
31359
+ var marker = parseMarkerAt(text, i);
31360
+ if (marker && shouldToggleFormatting(text, i, marker, state)) {
31361
+ flushBuffer();
31362
+ toggleFormatting(state, marker.type);
31363
+ i += marker.length;
31364
+ continue;
31365
+ }
31366
+ buffer += text[i];
31367
+ i++;
31368
+ }
31369
+ flushBuffer();
31370
+ }
31371
+ exports.parseInlineSegments = parseInlineSegments;
31372
+ function parseMarkerAt(text, index) {
31373
+ var remaining = text.substring(index);
31374
+ if (remaining.startsWith('~~')) {
31375
+ return { type: 'strikethrough', length: 2 };
31376
+ }
31377
+ if (remaining.startsWith('**')) {
31378
+ return { type: 'bold', length: 2 };
31379
+ }
31380
+ if (remaining.startsWith('*')) {
31381
+ return { type: 'italic', length: 1 };
31382
+ }
31383
+ return null;
31384
+ }
31385
+ function shouldToggleFormatting(text, index, marker, currentState) {
31386
+ var isCurrentlyActive = getCurrentFormatState(currentState, marker.type);
31387
+ if (isCurrentlyActive) {
31388
+ return true;
31389
+ }
31390
+ // Opening marker must be followed by a non-whitespace character.
31391
+ var nextIndex = index + marker.length;
31392
+ var nextChar = nextIndex < text.length ? text.charAt(nextIndex) : '';
31393
+ if (nextChar.length === 0 || isWhitespace(nextChar)) {
31394
+ return false;
31395
+ }
31396
+ return true;
31397
+ }
31398
+ function isWhitespace(char) {
31399
+ return /\s/.test(char);
31400
+ }
31401
+ function toggleFormatting(state, type) {
31402
+ switch (type) {
31403
+ case 'bold':
31404
+ state.bold = !state.bold;
31405
+ break;
31406
+ case 'italic':
31407
+ state.italic = !state.italic;
31408
+ break;
31409
+ case 'strikethrough':
31410
+ state.strikethrough = !state.strikethrough;
31411
+ break;
31412
+ }
31413
+ }
31414
+ function getCurrentFormatState(state, type) {
31415
+ switch (type) {
31416
+ case 'bold':
31417
+ return state.bold;
31418
+ case 'italic':
31419
+ return state.italic;
31420
+ case 'strikethrough':
31421
+ return state.strikethrough;
31422
+ }
31423
+ }
31424
+ function createFormattedSegment(text, state, link) {
31425
+ var format = {};
31426
+ if (state.bold) {
31427
+ format.fontWeight = 'bold';
31428
+ }
31429
+ if (state.italic) {
31430
+ format.italic = true;
31431
+ }
31432
+ if (state.strikethrough) {
31433
+ format.strikethrough = true;
31434
+ }
31435
+ return (0, roosterjs_content_model_dom_1.createText)(text, format, link);
31436
+ }
31437
+ function isValidUrl(url) {
31378
31438
  if (!url) {
31379
31439
  return false;
31380
31440
  }
31381
- // Accept common non-http schemes and relative paths
31382
31441
  if (url.startsWith('data:') ||
31383
31442
  url.startsWith('blob:') ||
31384
31443
  url.startsWith('/') ||
@@ -31393,51 +31452,7 @@ var isValidUrl = function (url) {
31393
31452
  catch (_) {
31394
31453
  return false;
31395
31454
  }
31396
- };
31397
- function pushText(result, text) {
31398
- var last = result[result.length - 1];
31399
- if (last && last.type === 'text') {
31400
- last.text += text;
31401
- }
31402
- else {
31403
- result.push({ type: 'text', text: text, url: '' });
31404
- }
31405
31455
  }
31406
- /**
31407
- * @internal
31408
- */
31409
- function splitParagraphSegments(text) {
31410
- var result = [];
31411
- var lastIndex = 0;
31412
- var match = null;
31413
- while ((match = linkRegex.exec(text)) !== null) {
31414
- if (match.index > lastIndex) {
31415
- pushText(result, text.slice(lastIndex, match.index));
31416
- }
31417
- if (match[2] && match[3]) {
31418
- if (isValidUrl(match[3])) {
31419
- result.push({ type: 'link', text: match[2], url: match[3] });
31420
- }
31421
- else {
31422
- pushText(result, match[0]);
31423
- }
31424
- }
31425
- else if (match[5] && match[6]) {
31426
- if (isValidUrl(match[6])) {
31427
- result.push({ type: 'image', text: match[5], url: match[6] });
31428
- }
31429
- else {
31430
- pushText(result, match[0]);
31431
- }
31432
- }
31433
- lastIndex = linkRegex.lastIndex;
31434
- }
31435
- if (lastIndex < text.length) {
31436
- pushText(result, text.slice(lastIndex));
31437
- }
31438
- return result;
31439
- }
31440
- exports.splitParagraphSegments = splitParagraphSegments;
31441
31456
 
31442
31457
 
31443
31458
  /***/ },
@@ -31698,20 +31713,30 @@ function createMarkdownParagraph(paragraph, context) {
31698
31713
  }
31699
31714
  exports.createMarkdownParagraph = createMarkdownParagraph;
31700
31715
  function textProcessor(text) {
31701
- var markdownString = text.text;
31702
- if (text.link) {
31703
- markdownString = "[" + text.text + "](" + text.link.format.href + ")";
31704
- }
31705
- if (text.format.fontWeight == 'bold') {
31706
- markdownString = "**" + markdownString + "**";
31707
- }
31708
- if (text.format.strikethrough) {
31709
- markdownString = "~~" + markdownString + "~~";
31716
+ var _a = text.format, fontWeight = _a.fontWeight, italic = _a.italic, strikethrough = _a.strikethrough;
31717
+ var hasInlineFormat = fontWeight == 'bold' || italic || strikethrough;
31718
+ if (!hasInlineFormat) {
31719
+ return text.link ? "[" + text.text + "](" + text.link.format.href + ")" : text.text;
31720
+ }
31721
+ // Move leading/trailing whitespace outside the markers so the emitted
31722
+ // markdown is valid (CommonMark requires emphasis markers to hug
31723
+ // non-whitespace), e.g. "world " with <b> => " " + "**world**".
31724
+ var match = /^(\s*)([\s\S]*?)(\s*)$/.exec(text.text);
31725
+ var _b = (0, tslib_1.__read)(match ? match : ['', '', text.text, ''], 4), leading = _b[1], core = _b[2], trailing = _b[3];
31726
+ if (!core) {
31727
+ return text.text;
31728
+ }
31729
+ var inner = text.link ? "[" + core + "](" + text.link.format.href + ")" : core;
31730
+ if (fontWeight == 'bold') {
31731
+ inner = "**" + inner + "**";
31732
+ }
31733
+ if (strikethrough) {
31734
+ inner = "~~" + inner + "~~";
31710
31735
  }
31711
- if (text.format.italic) {
31712
- markdownString = "*" + markdownString + "*";
31736
+ if (italic) {
31737
+ inner = "*" + inner + "*";
31713
31738
  }
31714
- return markdownString;
31739
+ return "" + leading + inner + trailing;
31715
31740
  }
31716
31741
 
31717
31742
 
@@ -33632,7 +33657,11 @@ var EditPlugin = /** @class */ (function () {
33632
33657
  if (!hasCtrlOrMetaKey &&
33633
33658
  !event.rawEvent.isComposing &&
33634
33659
  event.rawEvent.keyCode !== DEAD_KEY) {
33635
- (0, keyboardEnter_1.keyboardEnter)(editor, rawEvent, this.options.formatsToPreserveOnMerge);
33660
+ var shouldHandleEnterKey = this.options.shouldHandleEnterKey;
33661
+ var handleNormalEnter = typeof shouldHandleEnterKey === 'function'
33662
+ ? shouldHandleEnterKey(editor)
33663
+ : shouldHandleEnterKey !== false;
33664
+ (0, keyboardEnter_1.keyboardEnter)(editor, rawEvent, handleNormalEnter, this.options.formatsToPreserveOnMerge);
33636
33665
  }
33637
33666
  break;
33638
33667
  default:
@@ -34627,11 +34656,11 @@ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-mo
34627
34656
  /**
34628
34657
  * @internal
34629
34658
  */
34630
- function keyboardEnter(editor, rawEvent, formatsToPreserveOnMerge) {
34659
+ function keyboardEnter(editor, rawEvent, handleNormalEnter, formatsToPreserveOnMerge) {
34631
34660
  if (formatsToPreserveOnMerge === void 0) { formatsToPreserveOnMerge = []; }
34632
34661
  var selection = editor.getDOMSelection();
34633
34662
  editor.formatContentModel(function (model, context) {
34634
- var _a;
34663
+ var _a, _b;
34635
34664
  // 1. delete the expanded selection if any, then merge paragraph
34636
34665
  var result = (0, roosterjs_content_model_dom_1.deleteSelection)(model, [], context);
34637
34666
  // 2. Add line break
@@ -34642,12 +34671,14 @@ function keyboardEnter(editor, rawEvent, formatsToPreserveOnMerge) {
34642
34671
  var steps = rawEvent.shiftKey
34643
34672
  ? []
34644
34673
  : [handleAutoLink_1.handleAutoLink, handleEnterOnList_1.handleEnterOnList, deleteEmptyQuote_1.deleteEmptyQuote];
34645
- steps.push((0, handleEnterOnParagraph_1.handleEnterOnParagraph)(formatsToPreserveOnMerge));
34674
+ if (handleNormalEnter || handleEnterForEntity((_a = result.insertPoint) === null || _a === void 0 ? void 0 : _a.paragraph)) {
34675
+ steps.push((0, handleEnterOnParagraph_1.handleEnterOnParagraph)(formatsToPreserveOnMerge));
34676
+ }
34646
34677
  (0, roosterjs_content_model_dom_1.runEditSteps)(steps, result);
34647
34678
  }
34648
34679
  if (result.deleteResult == 'range') {
34649
34680
  // We have deleted something, next input should inherit the segment format from deleted content, so set pending format here
34650
- context.newPendingFormat = (_a = result.insertPoint) === null || _a === void 0 ? void 0 : _a.marker.format;
34681
+ context.newPendingFormat = (_b = result.insertPoint) === null || _b === void 0 ? void 0 : _b.marker.format;
34651
34682
  (0, roosterjs_content_model_dom_1.normalizeContentModel)(model);
34652
34683
  rawEvent.preventDefault();
34653
34684
  return true;
@@ -34664,6 +34695,10 @@ function keyboardEnter(editor, rawEvent, formatsToPreserveOnMerge) {
34664
34695
  });
34665
34696
  }
34666
34697
  exports.keyboardEnter = keyboardEnter;
34698
+ function handleEnterForEntity(paragraph) {
34699
+ return (paragraph &&
34700
+ (paragraph.isImplicit || paragraph.segments.some(function (x) { return x.segmentType == 'Entity'; })));
34701
+ }
34667
34702
 
34668
34703
 
34669
34704
  /***/ },
@@ -39044,7 +39079,7 @@ var PastePlugin = /** @class */ (function () {
39044
39079
  var pasteType = event.pasteType;
39045
39080
  switch (pasteSource) {
39046
39081
  case 'wordDesktop':
39047
- (0, processPastedContentFromWordDesktop_1.processPastedContentFromWordDesktop)(event.domToModelOption, event.htmlBefore || event.clipboardData.rawHtml || '');
39082
+ (0, processPastedContentFromWordDesktop_1.processPastedContentFromWordDesktop)(event.domToModelOption, event.htmlBefore || event.clipboardData.rawHtml || '', event.globalCssRules);
39048
39083
  break;
39049
39084
  case 'wacComponents':
39050
39085
  (0, processPastedContentWacComponents_1.processPastedContentWacComponents)(event);
@@ -39681,13 +39716,17 @@ var removeNegativeTextIndentParser_1 = __webpack_require__(/*! ../parsers/remove
39681
39716
  var setProcessor_1 = __webpack_require__(/*! ../utils/setProcessor */ "./packages/roosterjs-content-model-plugins/lib/paste/utils/setProcessor.ts");
39682
39717
  var wordContainerParser_1 = __webpack_require__(/*! ../parsers/wordContainerParser */ "./packages/roosterjs-content-model-plugins/lib/paste/parsers/wordContainerParser.ts");
39683
39718
  var wordTableParser_1 = __webpack_require__(/*! ../parsers/wordTableParser */ "./packages/roosterjs-content-model-plugins/lib/paste/parsers/wordTableParser.ts");
39719
+ var removeListParagraphMargins_1 = __webpack_require__(/*! ./removeListParagraphMargins */ "./packages/roosterjs-content-model-plugins/lib/paste/WordDesktop/removeListParagraphMargins.ts");
39684
39720
  /**
39685
39721
  * @internal
39686
39722
  * Handles pasted content when the source is Word Desktop.
39687
39723
  * @param domToModelOption Options for DOM to Content Model conversion
39688
39724
  * @param htmlString The HTML string to process
39725
+ * @param globalCssRules Global CSS rules extracted from the pasted document
39689
39726
  */
39690
- function processPastedContentFromWordDesktop(domToModelOption, htmlString) {
39727
+ function processPastedContentFromWordDesktop(domToModelOption, htmlString, globalCssRules) {
39728
+ if (globalCssRules === void 0) { globalCssRules = []; }
39729
+ (0, removeListParagraphMargins_1.removeListParagraphMargins)(globalCssRules);
39691
39730
  var metadataMap = (0, getStyleMetadata_1.getStyleMetadata)(htmlString);
39692
39731
  (0, setProcessor_1.setProcessor)(domToModelOption, 'element', wordDesktopElementProcessor(metadataMap));
39693
39732
  (0, addParser_1.addParser)(domToModelOption, 'block', adjustPercentileLineHeightParser_1.adjustPercentileLineHeight);
@@ -39958,6 +39997,96 @@ function getBulletElement(element) {
39958
39997
  }
39959
39998
 
39960
39999
 
40000
+ /***/ },
40001
+
40002
+ /***/ "./packages/roosterjs-content-model-plugins/lib/paste/WordDesktop/removeListParagraphMargins.ts"
40003
+ /*!******************************************************************************************************!*\
40004
+ !*** ./packages/roosterjs-content-model-plugins/lib/paste/WordDesktop/removeListParagraphMargins.ts ***!
40005
+ \******************************************************************************************************/
40006
+ (__unused_webpack_module, exports) {
40007
+
40008
+ "use strict";
40009
+
40010
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
40011
+ exports.removeListParagraphMargins = void 0;
40012
+ /**
40013
+ * CSS class selectors used by Word Desktop to mark list paragraph elements.
40014
+ * Word emits global CSS rules that apply margins to these classes, which we want
40015
+ * to suppress so that RoosterJS list indentation logic is used instead.
40016
+ */
40017
+ var WORD_LIST_PARAGRAPH_SELECTORS = new Set([
40018
+ 'p.MsoListParagraph',
40019
+ 'p.MsoListParagraphCxSpFirst',
40020
+ 'p.MsoListParagraphCxSpMiddle',
40021
+ 'p.MsoListParagraphCxSpLast',
40022
+ 'div.MsoListParagraph',
40023
+ 'div.MsoListParagraphCxSpFirst',
40024
+ 'div.MsoListParagraphCxSpMiddle',
40025
+ 'div.MsoListParagraphCxSpLast',
40026
+ ]);
40027
+ /**
40028
+ * @internal
40029
+ * Strips all margin-* properties from a CSS property string.
40030
+ * Empty tokens produced by a trailing semicolon are preserved so that the
40031
+ * resulting string still ends with ";" and remains safe to concatenate.
40032
+ * For example, "margin-top: 0pt; color: red;" becomes " color: red;".
40033
+ */
40034
+ function removeMarginProperties(cssText) {
40035
+ return cssText
40036
+ .split(';')
40037
+ .filter(function (prop) {
40038
+ var name = prop.split(':')[0].trim().toLowerCase();
40039
+ // Keep empty tokens (the trailing ';' produces one) and any non-margin property.
40040
+ return !name || !/^margin/.test(name);
40041
+ })
40042
+ .join(';');
40043
+ }
40044
+ /**
40045
+ * @internal
40046
+ * Removes margin properties from global CSS rules that target Word list paragraph
40047
+ * classes (p.MsoListParagraph, p.MsoListParagraphCxSpFirst, etc.).
40048
+ *
40049
+ * Word Desktop pastes a global stylesheet that typically includes rules like:
40050
+ * p.MsoListParagraph { margin: 0in; margin-bottom: .0001pt; ... }
40051
+ * These margins conflict with RoosterJS's own list indentation, causing double
40052
+ * indentation when the CSS is converted to inline styles via convertInlineCss.
40053
+ *
40054
+ * When a rule's selectors are exclusively list paragraph classes the margins are
40055
+ * removed in place. When a rule groups list paragraph classes with other selectors
40056
+ * the rule is split: the non-list selectors keep the original text, and a new rule
40057
+ * is inserted for the list paragraph selectors with margins stripped.
40058
+ *
40059
+ * The array is mutated in place so the changes are reflected when convertInlineCss
40060
+ * subsequently processes the same array reference.
40061
+ */
40062
+ function removeListParagraphMargins(globalCssRules) {
40063
+ // Iterate in reverse so that splice insertions don't shift unvisited indices.
40064
+ for (var i = globalCssRules.length - 1; i >= 0; i--) {
40065
+ var rule = globalCssRules[i];
40066
+ var matchingSelectors = rule.selectors.filter(function (s) { return WORD_LIST_PARAGRAPH_SELECTORS.has(s); });
40067
+ if (matchingSelectors.length === 0) {
40068
+ continue;
40069
+ }
40070
+ var nonMatchingSelectors = rule.selectors.filter(function (s) { return !WORD_LIST_PARAGRAPH_SELECTORS.has(s); });
40071
+ if (nonMatchingSelectors.length === 0) {
40072
+ // All selectors target list paragraphs — strip margins directly.
40073
+ rule.text = removeMarginProperties(rule.text);
40074
+ }
40075
+ else {
40076
+ // Mixed rule: keep the non-list selectors on the original entry, then
40077
+ // insert a new entry immediately after for the list paragraph selectors
40078
+ // with margins removed.
40079
+ rule.selectors = nonMatchingSelectors;
40080
+ globalCssRules.splice(i + 1, 0, {
40081
+ selectors: matchingSelectors,
40082
+ text: removeMarginProperties(rule.text),
40083
+ });
40084
+ }
40085
+ }
40086
+ }
40087
+ exports.removeListParagraphMargins = removeListParagraphMargins;
40088
+
40089
+
39961
40090
  /***/ },
39962
40091
 
39963
40092
  /***/ "./packages/roosterjs-content-model-plugins/lib/paste/oneNote/processPastedContentFromOneNote.ts"