roosterjs 9.54.0 → 9.55.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.
@@ -1,4 +1,4 @@
1
- // Type definitions for roosterjs (Version 9.54.0)
1
+ // Type definitions for roosterjs (Version 9.55.0)
2
2
  // Generated by dts tool from roosterjs
3
3
  // Project: https://github.com/Microsoft/roosterjs
4
4
 
@@ -7871,7 +7871,7 @@ export function normalizeFontFamily(fontFamily: string): string;
7871
7871
  * @param allowedCustomPasteType Allowed custom content type when paste besides text/plain, text/html and images
7872
7872
  Only text types are supported, and do not add "text/" prefix to the type values
7873
7873
  */
7874
- export function extractClipboardItems(items: DataTransferItem[], allowedCustomPasteType?: string[]): Promise<ClipboardData>;
7874
+ export function extractClipboardItems(items: DataTransferItem[], allowedCustomPasteType?: string[], isPasteNative?: boolean): Promise<ClipboardData>;
7875
7875
 
7876
7876
  /**
7877
7877
  * Gets the cached event data by cache key from event object if there is already one.
@@ -8108,6 +8108,13 @@ export function setSelection(group: ReadonlyContentModelBlockGroup, start?: Read
8108
8108
  */
8109
8109
  export function cloneModel(model: ReadonlyContentModelDocument, options?: CloneModelOptions): ContentModelDocument;
8110
8110
 
8111
+ /**
8112
+ * Clone a content model for paste operations, ensuring that cached elements are handled appropriately.
8113
+ * @param model The content model to clone
8114
+ * @returns A cloned content model suitable for paste operations
8115
+ */
8116
+ export function cloneModelForPaste(model: ReadonlyContentModelDocument): ContentModelDocument;
8117
+
8111
8118
  /**
8112
8119
  * Merge source model into target mode
8113
8120
  * @param target Target Content Model that will merge content into
@@ -11042,5 +11049,10 @@ export interface MarkdownPasteOptions {
11042
11049
  * @default false
11043
11050
  */
11044
11051
  autoConversion: boolean;
11052
+ /**
11053
+ * When true, the plugin will undo the markdown conversion when the user undoes the action.
11054
+ * @default false
11055
+ */
11056
+ undoConversion: boolean;
11045
11057
  }
11046
11058
 
@@ -6751,7 +6751,7 @@ var formatSegmentWithContentModel_1 = __webpack_require__(/*! ../utils/formatSeg
6751
6751
  */
6752
6752
  function changeCapitalization(editor, capitalization, language) {
6753
6753
  editor.focus();
6754
- (0, formatSegmentWithContentModel_1.formatSegmentWithContentModel)(editor, 'changeCapitalization', function (_, __, segment) {
6754
+ (0, formatSegmentWithContentModel_1.formatSegmentWithContentModel)(editor, 'changeCapitalization', function (_, __, segment, paragraph) {
6755
6755
  if ((segment === null || segment === void 0 ? void 0 : segment.segmentType) == 'Text') {
6756
6756
  switch (capitalization) {
6757
6757
  case 'lowerCase':
@@ -6762,7 +6762,13 @@ function changeCapitalization(editor, capitalization, language) {
6762
6762
  break;
6763
6763
  case 'capitalize':
6764
6764
  var wordArray = segment.text.toLocaleLowerCase(language).split(' ');
6765
- for (var i = 0; i < wordArray.length; i++) {
6765
+ // When a collapsed selection is in the middle of a word, the word is split
6766
+ // into multiple text segments around the selection marker. In that case the
6767
+ // first segment of the word continues from a previous segment, so its first
6768
+ // word must not be capitalized to avoid results like "HeLlo" for "he|llo".
6769
+ var precedingChar = getPrecedingCharacter(paragraph, segment);
6770
+ var startIndex = precedingChar && precedingChar != ' ' ? 1 : 0;
6771
+ for (var i = startIndex; i < wordArray.length; i++) {
6766
6772
  wordArray[i] =
6767
6773
  wordArray[i].charAt(0).toLocaleUpperCase(language) +
6768
6774
  wordArray[i].slice(1);
@@ -6786,6 +6792,30 @@ function changeCapitalization(editor, capitalization, language) {
6786
6792
  });
6787
6793
  }
6788
6794
  exports.changeCapitalization = changeCapitalization;
6795
+ /**
6796
+ * Get the character immediately preceding the given segment within its paragraph, skipping
6797
+ * selection markers (which carry no text). Returns an empty string if there is no preceding
6798
+ * text character (e.g. the segment starts the paragraph or follows a non-text segment).
6799
+ */
6800
+ function getPrecedingCharacter(paragraph, segment) {
6801
+ if (!paragraph) {
6802
+ return '';
6803
+ }
6804
+ var index = paragraph.segments.indexOf(segment);
6805
+ for (var i = index - 1; i >= 0; i--) {
6806
+ var previous = paragraph.segments[i];
6807
+ if (previous.segmentType == 'SelectionMarker') {
6808
+ continue;
6809
+ }
6810
+ else if (previous.segmentType == 'Text' && previous.text.length > 0) {
6811
+ return previous.text[previous.text.length - 1];
6812
+ }
6813
+ else {
6814
+ break;
6815
+ }
6816
+ }
6817
+ return '';
6818
+ }
6789
6819
 
6790
6820
 
6791
6821
  /***/ },
@@ -9348,21 +9378,11 @@ exports.generatePasteOptionFromPlugins = generatePasteOptionFromPlugins;
9348
9378
  "use strict";
9349
9379
 
9350
9380
  Object.defineProperty(exports, "__esModule", ({ value: true }));
9351
- exports.mergePasteContent = exports.cloneModelForPaste = void 0;
9381
+ exports.mergePasteContent = void 0;
9352
9382
  var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
9353
9383
  var createDomToModelContextForSanitizing_1 = __webpack_require__(/*! ../createModelFromHtml/createDomToModelContextForSanitizing */ "./packages/roosterjs-content-model-core/lib/command/createModelFromHtml/createDomToModelContextForSanitizing.ts");
9354
9384
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
9355
9385
  var BlackColor = 'rgb(0,0,0)';
9356
- var CloneOption = {
9357
- includeCachedElement: function (node, type) { return (type == 'cache' ? undefined : node); },
9358
- };
9359
- /**
9360
- * @internal
9361
- */
9362
- function cloneModelForPaste(model) {
9363
- return (0, roosterjs_content_model_dom_1.cloneModel)(model, CloneOption);
9364
- }
9365
- exports.cloneModelForPaste = cloneModelForPaste;
9366
9386
  /**
9367
9387
  * @internal
9368
9388
  */
@@ -9370,7 +9390,7 @@ function mergePasteContent(editor, eventResult, isFirstPaste) {
9370
9390
  var fragment = eventResult.fragment, domToModelOption = eventResult.domToModelOption, customizedMerge = eventResult.customizedMerge, pasteType = eventResult.pasteType, clipboardData = eventResult.clipboardData, containsBlockElements = eventResult.containsBlockElements;
9371
9391
  editor.formatContentModel(function (model, context) {
9372
9392
  if (!isFirstPaste && clipboardData.modelBeforePaste) {
9373
- var clonedModel = cloneModelForPaste(clipboardData.modelBeforePaste);
9393
+ var clonedModel = (0, roosterjs_content_model_dom_1.cloneModelForPaste)(clipboardData.modelBeforePaste);
9374
9394
  model.blocks = clonedModel.blocks;
9375
9395
  }
9376
9396
  var domToModelContext = (0, createDomToModelContextForSanitizing_1.createDomToModelContextForSanitizing)(editor.getDocument(), undefined /*defaultFormat*/, editor.getEnvironment().domToModelSettings.customized, domToModelOption, editor.getDOMHelper());
@@ -9449,10 +9469,11 @@ function getLastSegmentFormat(pasteModel) {
9449
9469
  Object.defineProperty(exports, "__esModule", ({ value: true }));
9450
9470
  exports.paste = void 0;
9451
9471
  var cleanHtmlComments_1 = __webpack_require__(/*! ./cleanHtmlComments */ "./packages/roosterjs-content-model-core/lib/command/paste/cleanHtmlComments.ts");
9452
- var mergePasteContent_1 = __webpack_require__(/*! ./mergePasteContent */ "./packages/roosterjs-content-model-core/lib/command/paste/mergePasteContent.ts");
9472
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
9453
9473
  var convertInlineCss_1 = __webpack_require__(/*! ../createModelFromHtml/convertInlineCss */ "./packages/roosterjs-content-model-core/lib/command/createModelFromHtml/convertInlineCss.ts");
9454
9474
  var createPasteFragment_1 = __webpack_require__(/*! ./createPasteFragment */ "./packages/roosterjs-content-model-core/lib/command/paste/createPasteFragment.ts");
9455
9475
  var generatePasteOptionFromPlugins_1 = __webpack_require__(/*! ./generatePasteOptionFromPlugins */ "./packages/roosterjs-content-model-core/lib/command/paste/generatePasteOptionFromPlugins.ts");
9476
+ var mergePasteContent_1 = __webpack_require__(/*! ./mergePasteContent */ "./packages/roosterjs-content-model-core/lib/command/paste/mergePasteContent.ts");
9456
9477
  var retrieveHtmlInfo_1 = __webpack_require__(/*! ./retrieveHtmlInfo */ "./packages/roosterjs-content-model-core/lib/command/paste/retrieveHtmlInfo.ts");
9457
9478
  /**
9458
9479
  * Paste into editor using a clipboardData object
@@ -9468,7 +9489,7 @@ function paste(editor, clipboardData, pasteTypeOrGetter) {
9468
9489
  if (!clipboardData.modelBeforePaste) {
9469
9490
  isFirstPaste = true;
9470
9491
  editor.formatContentModel(function (model) {
9471
- clipboardData.modelBeforePaste = (0, mergePasteContent_1.cloneModelForPaste)(model);
9492
+ clipboardData.modelBeforePaste = (0, roosterjs_content_model_dom_1.cloneModelForPaste)(model);
9472
9493
  return false;
9473
9494
  });
9474
9495
  }
@@ -12753,7 +12774,7 @@ var CopyPastePlugin = /** @class */ (function () {
12753
12774
  var dataTransfer = event.clipboardData;
12754
12775
  if (shouldPreventDefaultPaste(dataTransfer, editor_1)) {
12755
12776
  event.preventDefault();
12756
- (0, roosterjs_content_model_dom_1.extractClipboardItems)((0, roosterjs_content_model_dom_1.toArray)(dataTransfer.items), _this.state.allowedCustomPasteType).then(function (clipboardData) {
12777
+ (0, roosterjs_content_model_dom_1.extractClipboardItems)((0, roosterjs_content_model_dom_1.toArray)(dataTransfer.items), _this.state.allowedCustomPasteType, true /* isPasteNative */).then(function (clipboardData) {
12757
12778
  if (!editor_1.isDisposed()) {
12758
12779
  (0, paste_1.paste)(editor_1, clipboardData, _this.state.defaultPasteType);
12759
12780
  }
@@ -19773,7 +19794,7 @@ var ContentHandlers = (_a = {},
19773
19794
  * @param allowedCustomPasteType Allowed custom content type when paste besides text/plain, text/html and images
19774
19795
  Only text types are supported, and do not add "text/" prefix to the type values
19775
19796
  */
19776
- function extractClipboardItems(items, allowedCustomPasteType) {
19797
+ function extractClipboardItems(items, allowedCustomPasteType, isPasteNative) {
19777
19798
  var data = {
19778
19799
  types: [],
19779
19800
  text: '',
@@ -19781,7 +19802,7 @@ function extractClipboardItems(items, allowedCustomPasteType) {
19781
19802
  files: [],
19782
19803
  rawHtml: null,
19783
19804
  customValues: {},
19784
- pasteNativeEvent: true,
19805
+ pasteNativeEvent: !!isPasteNative,
19785
19806
  };
19786
19807
  return Promise.all((items || []).map(function (item) {
19787
19808
  var type = item.type;
@@ -20722,6 +20743,7 @@ function pruneUnselectedModel(model) {
20722
20743
  exports.pruneUnselectedModel = pruneUnselectedModel;
20723
20744
  function pruneUnselectedModelInternal(model, isSelectionAfterElement) {
20724
20745
  var e_1, _a, _b;
20746
+ var _c;
20725
20747
  for (var index = model.blocks.length - 1; index >= 0; index--) {
20726
20748
  var block = model.blocks[index];
20727
20749
  switch (block.blockType) {
@@ -20745,15 +20767,17 @@ function pruneUnselectedModelInternal(model, isSelectionAfterElement) {
20745
20767
  case 'Paragraph':
20746
20768
  var newSegments = [];
20747
20769
  try {
20748
- for (var _c = (e_1 = void 0, (0, tslib_1.__values)(block.segments)), _d = _c.next(); !_d.done; _d = _c.next()) {
20749
- var segment = _d.value;
20770
+ for (var _d = (e_1 = void 0, (0, tslib_1.__values)(block.segments)), _e = _d.next(); !_e.done; _e = _d.next()) {
20771
+ var segment = _e.value;
20772
+ var isSelectedOrUndeletable = segment.isSelected || ((_c = segment.link) === null || _c === void 0 ? void 0 : _c.format.undeletable);
20750
20773
  if (segment.segmentType == 'General') {
20751
20774
  pruneUnselectedModel(segment);
20752
- if (segment.blocks.length > 0 || segment.isSelected) {
20775
+ if (segment.blocks.length > 0 || isSelectedOrUndeletable) {
20753
20776
  newSegments.push(segment);
20754
20777
  }
20755
20778
  }
20756
- else if (segment.isSelected && segment.segmentType != 'SelectionMarker') {
20779
+ else if (isSelectedOrUndeletable &&
20780
+ segment.segmentType != 'SelectionMarker') {
20757
20781
  newSegments.push(segment);
20758
20782
  }
20759
20783
  }
@@ -20761,7 +20785,7 @@ function pruneUnselectedModelInternal(model, isSelectionAfterElement) {
20761
20785
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
20762
20786
  finally {
20763
20787
  try {
20764
- if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
20788
+ if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
20765
20789
  }
20766
20790
  finally { if (e_1) throw e_1.error; }
20767
20791
  }
@@ -23734,8 +23758,8 @@ exports.shouldSetValue = shouldSetValue;
23734
23758
  Object.defineProperty(exports, "__esModule", ({ value: true }));
23735
23759
  exports.createImage = exports.createText = exports.createTableCell = exports.createTable = exports.createSelectionMarker = exports.createParagraph = exports.createFormatContainer = exports.createListItem = exports.createBr = exports.isLinkUndeletable = exports.setLinkUndeletable = exports.scrollRectIntoView = exports.normalizeRect = exports.isWhiteSpacePreserved = exports.reuseCachedElement = exports.findClosestBlockEntityContainer = exports.isBlockEntityContainer = exports.isEntityDelimiter = exports.addDelimiters = exports.generateEntityClassNames = exports.parseEntityFormat = exports.getAllEntityWrappers = exports.findClosestEntityWrapper = exports.isEntityElement = exports.unwrap = exports.wrap = exports.wrapAllChildNodes = exports.moveChildNodes = exports.toArray = exports.getSafeIdSelector = exports.getObjectKeys = exports.isElementOfType = exports.isNodeOfType = exports.hasMetadata = exports.getMetadata = exports.updateMetadata = exports.buildSelectionMarker = exports.isBlockElement = exports.areSameFormats = exports.parseFormat = exports.getRegularSelectionOffsets = exports.formatContainerProcessor = exports.tableProcessor = exports.entityProcessor = exports.processChildNode = exports.handleRegularSelection = exports.childProcessor = exports.contentModelToText = exports.contentModelToDom = exports.domToContentModel = void 0;
23736
23760
  exports.trimModelForSelection = exports.getDOMInsertPointRect = exports.getSelectionRootNode = exports.isBold = exports.createModelToDomConfig = exports.createModelToDomContextWithConfig = exports.createModelToDomContext = exports.createDomToModelConfig = exports.createDomToModelContextWithConfig = exports.createDomToModelContext = exports.defaultGenerateColorKey = exports.parseColor = exports.setColor = exports.getColor = exports.DeprecatedColors = exports.BorderKeys = exports.parseValueWithUnit = exports.getAutoListStyleType = exports.getOrderedListNumberStr = exports.ParagraphFormats = exports.ListFormatsToMove = exports.ListFormatsToKeep = exports.ListFormats = exports.copyFormat = exports.setParagraphNotImplicit = exports.normalizeSegmentFormat = exports.mergeTextSegments = exports.normalizeSingleSegment = exports.isEmpty = exports.addSegment = exports.unwrapBlock = exports.isGeneralSegment = exports.normalizeContentModel = exports.normalizeParagraph = exports.addTextSegment = exports.addLink = exports.addCode = exports.addBlock = exports.mutateSegment = exports.mutateSegments = exports.mutateBlock = exports.createTableRow = exports.createEmptyModel = exports.createListLevel = exports.createDivider = exports.createEntity = exports.createGeneralBlock = exports.createGeneralSegment = exports.createParagraphDecorator = exports.createContentModelDocument = void 0;
23737
- exports.runEditSteps = exports.getClosestAncestorBlockGroupIndex = exports.getSegmentTextFormat = exports.getListStyleTypeFromString = exports.retrieveModelFormatState = exports.setTableCellBackgroundColor = exports.MIN_ALLOWED_TABLE_CELL_HEIGHT = exports.MIN_ALLOWED_TABLE_CELL_WIDTH = exports.normalizeTable = exports.setFirstColumnFormatBorders = exports.applyTableFormat = exports.deleteBlock = exports.deleteSegment = exports.deleteSelection = exports.mergeModel = exports.cloneModel = exports.setSelection = exports.hasSelectionInBlockGroup = exports.hasSelectionInSegment = exports.hasSelectionInBlock = exports.getSelectedCells = exports.getSelectedSegmentsAndParagraphs = exports.getSelectedSegments = exports.getSelectedParagraphs = exports.getOperationalBlocks = exports.getFirstSelectedTable = exports.getFirstSelectedListItem = exports.iterateSelections = exports.isBlockGroupOfType = exports.getRangesByText = exports.getImageState = exports.setImageState = exports.getParagraphMarker = exports.setParagraphMarker = exports.cacheGetEventData = exports.extractClipboardItems = exports.normalizeFontFamily = exports.transformColor = exports.retrieveDocumentMetadata = exports.readFile = exports.parseTableCells = exports.normalizeText = exports.isSpace = exports.isPunctuation = exports.extractBorderValues = exports.combineBorderValue = exports.getNodePositionFromEvent = exports.isCursorMovingKey = exports.isModifierKey = exports.isCharacterValue = void 0;
23738
- exports.EmptySegmentFormat = exports.UnorderedListStyleMap = exports.OrderedListStyleMap = exports.TableBorderFormat = exports.NumberingListType = exports.BulletListType = exports.ChangeSource = exports.ListMetadataDefinition = exports.getListMetadata = exports.updateListMetadata = exports.getTableMetadata = exports.updateTableMetadata = exports.getTableCellMetadata = exports.updateTableCellMetadata = exports.getImageMetadata = exports.updateImageMetadata = void 0;
23761
+ exports.getClosestAncestorBlockGroupIndex = exports.getSegmentTextFormat = exports.getListStyleTypeFromString = exports.retrieveModelFormatState = exports.setTableCellBackgroundColor = exports.MIN_ALLOWED_TABLE_CELL_HEIGHT = exports.MIN_ALLOWED_TABLE_CELL_WIDTH = exports.normalizeTable = exports.setFirstColumnFormatBorders = exports.applyTableFormat = exports.deleteBlock = exports.deleteSegment = exports.deleteSelection = exports.mergeModel = exports.cloneModelForPaste = exports.cloneModel = exports.setSelection = exports.hasSelectionInBlockGroup = exports.hasSelectionInSegment = exports.hasSelectionInBlock = exports.getSelectedCells = exports.getSelectedSegmentsAndParagraphs = exports.getSelectedSegments = exports.getSelectedParagraphs = exports.getOperationalBlocks = exports.getFirstSelectedTable = exports.getFirstSelectedListItem = exports.iterateSelections = exports.isBlockGroupOfType = exports.getRangesByText = exports.getImageState = exports.setImageState = exports.getParagraphMarker = exports.setParagraphMarker = exports.cacheGetEventData = exports.extractClipboardItems = exports.normalizeFontFamily = exports.transformColor = exports.retrieveDocumentMetadata = exports.readFile = exports.parseTableCells = exports.normalizeText = exports.isSpace = exports.isPunctuation = exports.extractBorderValues = exports.combineBorderValue = exports.getNodePositionFromEvent = exports.isCursorMovingKey = exports.isModifierKey = exports.isCharacterValue = void 0;
23762
+ exports.EmptySegmentFormat = exports.UnorderedListStyleMap = exports.OrderedListStyleMap = exports.TableBorderFormat = exports.NumberingListType = exports.BulletListType = exports.ChangeSource = exports.ListMetadataDefinition = exports.getListMetadata = exports.updateListMetadata = exports.getTableMetadata = exports.updateTableMetadata = exports.getTableCellMetadata = exports.updateTableCellMetadata = exports.getImageMetadata = exports.updateImageMetadata = exports.runEditSteps = void 0;
23739
23763
  var domToContentModel_1 = __webpack_require__(/*! ./domToModel/domToContentModel */ "./packages/roosterjs-content-model-dom/lib/domToModel/domToContentModel.ts");
23740
23764
  Object.defineProperty(exports, "domToContentModel", ({ enumerable: true, get: function () { return domToContentModel_1.domToContentModel; } }));
23741
23765
  var contentModelToDom_1 = __webpack_require__(/*! ./modelToDom/contentModelToDom */ "./packages/roosterjs-content-model-dom/lib/modelToDom/contentModelToDom.ts");
@@ -23966,6 +23990,7 @@ var setSelection_1 = __webpack_require__(/*! ./modelApi/selection/setSelection *
23966
23990
  Object.defineProperty(exports, "setSelection", ({ enumerable: true, get: function () { return setSelection_1.setSelection; } }));
23967
23991
  var cloneModel_1 = __webpack_require__(/*! ./modelApi/editing/cloneModel */ "./packages/roosterjs-content-model-dom/lib/modelApi/editing/cloneModel.ts");
23968
23992
  Object.defineProperty(exports, "cloneModel", ({ enumerable: true, get: function () { return cloneModel_1.cloneModel; } }));
23993
+ Object.defineProperty(exports, "cloneModelForPaste", ({ enumerable: true, get: function () { return cloneModel_1.cloneModelForPaste; } }));
23969
23994
  var mergeModel_1 = __webpack_require__(/*! ./modelApi/editing/mergeModel */ "./packages/roosterjs-content-model-dom/lib/modelApi/editing/mergeModel.ts");
23970
23995
  Object.defineProperty(exports, "mergeModel", ({ enumerable: true, get: function () { return mergeModel_1.mergeModel; } }));
23971
23996
  var deleteSelection_1 = __webpack_require__(/*! ./modelApi/editing/deleteSelection */ "./packages/roosterjs-content-model-dom/lib/modelApi/editing/deleteSelection.ts");
@@ -24795,7 +24820,34 @@ exports.normalizeAllSegments = normalizeAllSegments;
24795
24820
  function normalizeSingleSegment(paragraph, segment, ignoreTrailingSpaces) {
24796
24821
  if (ignoreTrailingSpaces === void 0) { ignoreTrailingSpaces = false; }
24797
24822
  var context = resetNormalizeSegmentContext();
24823
+ var index = paragraph.segments.indexOf(segment);
24798
24824
  context.ignoreTrailingSpaces = ignoreTrailingSpaces;
24825
+ // Search backward for the nearest non-empty text segment (skipping SelectionMarkers and empty text),
24826
+ // to determine whether leading spaces of the current segment should be preserved.
24827
+ // If the previous text doesn't end with a space, keep the leading space to maintain word separation.
24828
+ for (var i = index - 1; i >= 0; i--) {
24829
+ var s = paragraph.segments[i];
24830
+ if (s.segmentType == 'Text') {
24831
+ if (s.text.length > 0) {
24832
+ if (s.text.substr(-1) != SPACE) {
24833
+ context.ignoreLeadingSpaces = false;
24834
+ }
24835
+ break;
24836
+ }
24837
+ }
24838
+ else if (s.segmentType == 'Image') {
24839
+ // If the previous segment is an image, we should keep the leading space of the current segment to maintain word separation.
24840
+ context.ignoreLeadingSpaces = false;
24841
+ break;
24842
+ }
24843
+ else if (s.segmentType == 'Br') {
24844
+ // If the previous segment is a line break, we should ignore the leading space of the current segment.
24845
+ context.ignoreLeadingSpaces = true;
24846
+ }
24847
+ else if (s.segmentType != 'SelectionMarker') {
24848
+ break;
24849
+ }
24850
+ }
24799
24851
  normalizeSegment(paragraph, segment, context);
24800
24852
  }
24801
24853
  exports.normalizeSingleSegment = normalizeSingleSegment;
@@ -24836,6 +24888,10 @@ function normalizeSegment(paragraph, segment, context) {
24836
24888
  context.ignoreLeadingSpaces = false;
24837
24889
  break;
24838
24890
  case 'Text':
24891
+ // Skip empty text segments to avoid affecting normalization context
24892
+ if (segment.text.length == 0) {
24893
+ break;
24894
+ }
24839
24895
  context.textSegments.push(segment);
24840
24896
  context.lastInlineSegment = segment;
24841
24897
  context.lastTextSegment = segment;
@@ -24843,9 +24899,9 @@ function normalizeSegment(paragraph, segment, context) {
24843
24899
  var last = segment.text.substr(-1);
24844
24900
  if (!(0, hasSpacesOnly_1.hasSpacesOnly)(segment.text)) {
24845
24901
  if (first == SPACE) {
24846
- // 1. Multiple leading space => single &nbsp; or empty (depends on if previous segment ends with space)
24902
+ // 1. Multiple leading space => single space or empty (depends on if previous segment ends with space)
24847
24903
  (0, mutate_1.mutateSegment)(paragraph, segment, function (textSegment) {
24848
- textSegment.text = textSegment.text.replace(LEADING_SPACE_REGEX, context.ignoreLeadingSpaces ? '' : NONE_BREAK_SPACE);
24904
+ textSegment.text = textSegment.text.replace(LEADING_SPACE_REGEX, context.ignoreLeadingSpaces ? '' : SPACE);
24849
24905
  });
24850
24906
  }
24851
24907
  if (last == SPACE) {
@@ -25944,8 +26000,20 @@ function getBorderStyleFromColor(color) {
25944
26000
  "use strict";
25945
26001
 
25946
26002
  Object.defineProperty(exports, "__esModule", ({ value: true }));
25947
- exports.cloneModel = void 0;
26003
+ exports.cloneModel = exports.cloneModelForPaste = void 0;
25948
26004
  var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
26005
+ var CloneOption = {
26006
+ includeCachedElement: function (node, type) { return (type == 'cache' ? undefined : node); },
26007
+ };
26008
+ /**
26009
+ * Clone a content model for paste operations, ensuring that cached elements are handled appropriately.
26010
+ * @param model The content model to clone
26011
+ * @returns A cloned content model suitable for paste operations
26012
+ */
26013
+ function cloneModelForPaste(model) {
26014
+ return cloneModel(model, CloneOption);
26015
+ }
26016
+ exports.cloneModelForPaste = cloneModelForPaste;
25949
26017
  /**
25950
26018
  * Clone a content model
25951
26019
  * @param model The content model to clone
@@ -32019,11 +32087,12 @@ exports.modelProcessor = modelProcessor;
32019
32087
 
32020
32088
  Object.defineProperty(exports, "__esModule", ({ value: true }));
32021
32089
  exports.MarkdownPastePlugin = void 0;
32022
- var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
32023
32090
  var convertMarkdownToContentModel_1 = __webpack_require__(/*! ../markdownToModel/convertMarkdownToContentModel */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/convertMarkdownToContentModel.ts");
32024
32091
  var isPastedContentMarkdown_1 = __webpack_require__(/*! ../publicApi/isPastedContentMarkdown */ "./packages/roosterjs-content-model-markdown/lib/publicApi/isPastedContentMarkdown.ts");
32092
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
32025
32093
  var DefaultOptions = {
32026
32094
  autoConversion: false,
32095
+ undoConversion: false,
32027
32096
  };
32028
32097
  /**
32029
32098
  * Markdown paste plugin. Handles the BeforePaste event and, when the pasted content
@@ -32069,12 +32138,37 @@ var MarkdownPastePlugin = /** @class */ (function () {
32069
32138
  * @param event The event to handle:
32070
32139
  */
32071
32140
  MarkdownPastePlugin.prototype.onPluginEvent = function (event) {
32072
- if (!this.editor || event.eventType != 'beforePaste') {
32141
+ if (!this.editor) {
32073
32142
  return;
32074
32143
  }
32075
- var shouldConvert = event.pasteType === 'asMarkdown' || this.options.autoConversion;
32076
- if (shouldConvert && (0, isPastedContentMarkdown_1.isPastedContentMarkdown)(this.editor, event.clipboardData)) {
32077
- convertPastedTextToMarkdown(this.editor, event.fragment, event.clipboardData.text);
32144
+ if (event.eventType === 'contentChanged' &&
32145
+ event.source === roosterjs_content_model_dom_1.ChangeSource.Paste &&
32146
+ this.options.autoConversion &&
32147
+ event.data) {
32148
+ var clipboardData = event.data;
32149
+ var shouldConvert = clipboardData && clipboardData.pasteNativeEvent && this.options.autoConversion;
32150
+ if (shouldConvert &&
32151
+ (0, isPastedContentMarkdown_1.isPastedContentMarkdown)(this.editor, clipboardData) &&
32152
+ clipboardData.modelBeforePaste) {
32153
+ var modelBeforePaste_1 = (0, roosterjs_content_model_dom_1.cloneModelForPaste)(clipboardData.modelBeforePaste);
32154
+ (0, roosterjs_content_model_dom_1.mergeModel)(modelBeforePaste_1, (0, convertMarkdownToContentModel_1.convertMarkdownToContentModel)(clipboardData.text, { emptyLine: 'merge' }));
32155
+ if (this.options.undoConversion) {
32156
+ this.editor.takeSnapshot();
32157
+ }
32158
+ this.editor.formatContentModel(function (model) {
32159
+ model.blocks = modelBeforePaste_1.blocks;
32160
+ return true;
32161
+ }, {
32162
+ apiName: 'MarkdownConversion',
32163
+ scrollCaretIntoView: true,
32164
+ });
32165
+ }
32166
+ }
32167
+ else if (event.eventType === 'beforePaste' && !event.clipboardData.pasteNativeEvent) {
32168
+ var shouldConvert = event.pasteType === 'asMarkdown';
32169
+ if (shouldConvert && (0, isPastedContentMarkdown_1.isPastedContentMarkdown)(this.editor, event.clipboardData)) {
32170
+ convertPastedTextToMarkdown(this.editor, event.fragment, event.clipboardData.text);
32171
+ }
32078
32172
  }
32079
32173
  };
32080
32174
  return MarkdownPastePlugin;
@@ -38017,16 +38111,31 @@ function createImageWrapper(editor, image, options, editInfo, htmlOptions, opera
38017
38111
  croppers = (0, createImageCropper_1.createImageCropper)(doc);
38018
38112
  }
38019
38113
  var wrapper = createWrapper(editor, imageClone, options, editInfo, resizers, rotators, croppers);
38114
+ // Capture the image footprint before attaching the shadow root, since the light-DOM image
38115
+ // stops being rendered once the shadow root takes over.
38116
+ var imageWidth = image.offsetWidth;
38117
+ var imageHeight = image.offsetHeight;
38020
38118
  var imageSpan = (0, roosterjs_content_model_dom_1.wrap)(doc, image, 'span');
38021
- var shadowSpan = createShadowSpan(wrapper, imageSpan);
38119
+ var shadowSpan = createShadowSpan(wrapper, imageSpan, imageWidth, imageHeight);
38022
38120
  return { wrapper: wrapper, shadowSpan: shadowSpan, imageClone: imageClone, resizers: resizers, rotators: rotators, croppers: croppers };
38023
38121
  }
38024
38122
  exports.createImageWrapper = createImageWrapper;
38025
- var createShadowSpan = function (wrapper, imageSpan) {
38123
+ var createShadowSpan = function (wrapper, imageSpan, imageWidth, imageHeight) {
38026
38124
  var shadowRoot = imageSpan.attachShadow({
38027
38125
  mode: 'open',
38028
38126
  });
38029
38127
  imageSpan.id = IMAGE_EDIT_SHADOW_ROOT;
38128
+ // Pin the shadow host to the original image's box so that wrapping the image does not grow the
38129
+ // surrounding line box. Without this, the taller edit wrapper enlarges the line and the browser
38130
+ // scrolls the selection back into view, making the editor jump. The wrapper and handles still
38131
+ // overflow the host visually because overflow is left visible.
38132
+ if (imageWidth > 0 && imageHeight > 0) {
38133
+ imageSpan.style.display = 'inline-block';
38134
+ imageSpan.style.width = imageWidth + "px";
38135
+ imageSpan.style.height = imageHeight + "px";
38136
+ imageSpan.style.verticalAlign = 'bottom';
38137
+ imageSpan.style.overflow = 'visible';
38138
+ }
38030
38139
  shadowRoot.appendChild(wrapper);
38031
38140
  return imageSpan;
38032
38141
  };